It is currently 05 Nov 2025, 22:39
   
Text Size

Help implementing a card

Moderators: BetaSteward, noxx, jeffwadsworth, JayDi, TheElk801, LevelX, North, CCGHQ Admins

Re: Help implementing a card

Postby TGower » 25 May 2015, 07:20

There is probably a really simple answer to this, but I've been stuck on mystic remora for a few days. Here is what I came up with:
Code: Select all
package mage. sets. iceage;

import java. util. UUID;
import mage. abilities. costs. mana. ManaCostsImpl;
import mage. abilities. keyword. CumulativeUpkeepAbility;
import mage. game. stack. Spell;
import mage. constants. CardType;
import mage. constants. Rarity;
import mage. abilities. Ability;
import mage. abilities. TriggeredAbilityImpl;
import mage. abilities. costs. mana. GenericManaCost;
import mage. abilities. effects. OneShotEffect;
import mage. abilities. effects. common. DrawCardSourceControllerEffect;
import mage. cards. CardImpl;
import mage. constants. Outcome;
import mage. constants. Zone;
import mage. game. Game;
import mage. game. events. GameEvent;
import mage. players. Player;
import mage. target. targetpointer. FixedTarget;


/**
 *
 * @author TGower
 */
public class MysticRemora extends CardImpl {

    public MysticRemora(UUID ownerId) {
        super(ownerId, 87, "Mystic Remora", Rarity. COMMON, new CardType[]{CardType. ENCHANTMENT}, "{U}");
        this. expansionSetCode = "ICE";

        // Cumulative upkeep {1}
        this. addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}")));
        // Whenever an opponent casts a noncreature spell, you may draw a card unless that player pays {4}.
        this. addAbility(new MysticRemoraTriggeredAbility());
       
    }

    public MysticRemora(final MysticRemora card) {
        super(card);
    }

    @Override
    public MysticRemora copy() {
        return new MysticRemora(this);
    }
}

class MysticRemoraTriggeredAbility extends TriggeredAbilityImpl {
   

    public MysticRemoraTriggeredAbility() {
        super(Zone. BATTLEFIELD, new MysticRemoraEffect(), false);
       
    }

    public MysticRemoraTriggeredAbility(final MysticRemoraTriggeredAbility ability) {
        super(ability);
    }

    @Override
    public MysticRemoraTriggeredAbility copy() {
        return new MysticRemoraTriggeredAbility(this);
    }
   
    @Override
    public boolean checkEventType(GameEvent event, Game game) {
        return event. getType() == GameEvent. EventType. SPELL_CAST;
    }   
   
    @Override
    public boolean checkTrigger(GameEvent event, Game game) {
        if (game. getOpponents(controllerId). contains(event. getPlayerId())) {
            if (event. getType() == GameEvent. EventType. SPELL_CAST) {
                Spell spell = game. getStack(). getSpell(event. getTargetId());
                if (spell != null && !spell. getCardType(). contains(CardType. CREATURE)) {
                    Player controller = game. getPlayer(game. getControllerId(this. controllerId));
                    Player player = game. getPlayer(spell. getControllerId());
                    if (controller != player) {
                        this. getEffects(). get(0). setTargetPointer(new FixedTarget(event. getPlayerId()));
                    }
                return true;
                }
            }
        }
        return false;
    }
       
    @Override
    public String getRule() {
        return "Whenever an opponent casts a noncreature spell, you may draw a card unless that player pays {4}. ";
    }
}
   
    class MysticRemoraEffect extends OneShotEffect {

    public MysticRemoraEffect() {
        super(Outcome. DrawCard);
        this. staticText = "you may draw a card unless that player pays {4}";
    }

    public MysticRemoraEffect(final MysticRemoraEffect effect) {
        super(effect);
    }
   
    @Override
    public MysticRemoraEffect copy() {
        return new MysticRemoraEffect(this);
    }

    @Override
    public boolean apply(Game game, Ability source) {
        Player player = game. getPlayer(targetPointer. getFirst(game, source));
        Player controller = game. getPlayer(source. getControllerId());
        if (player != null) {
            GenericManaCost cost = new GenericManaCost(4);
            if (!cost. pay(source, game, player. getId(), player. getId(), false)) {               
                    controller. drawCards(1, game);
            }
            return true;
        }
        return false;
    }
}

   

   
(Spaces after ever . to avoid getting flagged by spam protection for "off-site URLs")It works except drawing a card should be optional for Remora's controller if the cost is not paid. It seems like DrawCardSourceControllerEffect(1, true) would do everything I am trying to do, but I'm not sure how to implement that given that we are already inside an effect, or if that is even possible.
TGower
 
Posts: 3
Joined: 18 May 2015, 19:04
Has thanked: 0 time
Been thanked: 0 time

Re: Help implementing a card

Postby LevelX » 25 May 2015, 08:24

Why not going to http://ct-magefree.rhcloud.com/, entering "you may % unless that" into Rule text search field and opening the code of Rhystic Study to know what to do.
You can do it probably for > than 80% of cards to implement. Sometimes it's useful combining code from different cards.

PS: Beginning with 4 (or 5 posts) you no longer need to add the blanks after the dots.
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby LoneFox » 23 Jun 2015, 05:12

I'm having problems with these cards:

Death Match:
Code: Select all
private final UUID originalId;

public DeathMatch(UUID ownerId) {
    super(ownerId, 136, "Death Match", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}");
    this.expansionSetCode = "ONS";

    // Whenever a creature enters the battlefield, that creature's controller may have target creature of his or her choice get -3/-3 until end of turn.
    Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-3, -3, Duration.EndOfTurn),
        new FilterCreaturePermanent(), true, SetTargetPointer.PLAYER, "");
    ability.addTarget(new TargetCreaturePermanent());
    this.addAbility(ability);
    originalId = ability.getOriginalId();
}

@Override
public void adjustTargets(Ability ability, Game game) {
    if(ability.getOriginalId().equals(originalId)) {
        UUID controllerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability);
        if(controllerId != null) {
            ability.getTargets().get(0).setTargetController(controllerId);
            ability.getEffects().get(0).setTargetPointer(new FirstTargetPointer());
        }
    }
}
This lets the correct player to choose the target, but then the controller of Death Match gets asked if they want to use the ability instead of the player who chose the target. How to I redirect that prompt to the right player?

Grab the Reins:
Code: Select all
public GrabTheReins(UUID ownerId) {
    super(ownerId, 95, "Grab the Reins", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{R}");
    this.expansionSetCode = "MRD";

    // Choose one -
    this.getSpellAbility().getModes().setMinModes(1);
    this.getSpellAbility().getModes().setMaxModes(1);
    // Until end of turn, you gain control of target creature and it gains haste;
    this.getSpellAbility().addTarget(new TargetCreaturePermanent());
    this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
    this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
    // or sacrifice a creature, then Grab the Reins deals damage equal to that creature's power to target creature or player.
    Mode mode = new Mode();
    mode.getEffects().add(new GrabTheReinsEffect());
    mode.getTargets().add(new TargetCreatureOrPlayer());
    this.getSpellAbility().getModes().addMode(mode);

    // Entwine {2}{R}
    this.addAbility(new EntwineAbility("{2}{R}"));
}
Both modes themselves work as expected, but for some reason they resolve in wrong order, meaning it's not possible to sacrifice the stolen creature, because it is still on opponent's side. I don't understand what is going on. Promise of Power is implemented in the same way, and there the modes resolve in correct order.

Cerulean Sphinx:
Code: Select all
// {U}: Cerulean Sphinx's owner shuffles it into his or her library.
Effect effect = new ShuffleIntoLibrarySourceEffect();
effect.setText("{this}'s owner shuffles it into his or her library.");
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{U}")));
Something gets shuffled into library, but the sphinx remains on the battlefield. Is ShuffleIntoLibrarySourceEffect bugged?
LoneFox
Programmer
 
Posts: 71
Joined: 08 Mar 2009, 13:43
Has thanked: 0 time
Been thanked: 7 times

Re: Help implementing a card

Postby LevelX » 23 Jun 2015, 09:29

LoneFox wrote:Cerulean Sphinx:
Code: Select all
// {U}: Cerulean Sphinx's owner shuffles it into his or her library.
Effect effect = new ShuffleIntoLibrarySourceEffect();
effect.setText("{this}'s owner shuffles it into his or her library.");
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{U}")));
Something gets shuffled into library, but the sphinx remains on the battlefield. Is ShuffleIntoLibrarySourceEffect bugged?
Fixed and committed ShuffleIntoLibrarySourceEffect. It was only used for and did only work for card objects and not for permanents. Now it does.
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby EvilGeek » 25 Jun 2015, 16:15

I'm trying to implement Unnatural Selection, and it's very difficult for me. I've managed to get this far, however I'm not sure if:
A: I'm extending the right effect and using the right outcome.
B: I'm getting the type choice correctly.
C: How to change the target's type until end of turn.

Code attached as site says "Your post looks too spamy for a new user, please remove off-site URLs." even though it's code and has no URL's. Silly site, can't spell or tell when something is code...

Any help will be greatly appreciated. (Once this is done, I can do three more cards with the EXACT same effect.)

Thanks.
Attachments
UnnaturalSelection.txt
(4.62 KiB) Downloaded 377 times
EvilGeek
 
Posts: 8
Joined: 27 Nov 2014, 16:56
Has thanked: 0 time
Been thanked: 0 time

Re: Help implementing a card

Postby LevelX » 25 Jun 2015, 20:33

EvilGeek wrote:I'm trying to implement Unnatural Selection, and it's very difficult for me. I've managed to get this far, however I'm not sure if:
A: I'm extending the right effect and using the right outcome.
B: I'm getting the type choice correctly.
Looks good so far.

EvilGeek wrote:C: How to change the target's type until end of turn.

Thanks.
I added the needed framework effect (not tested).
See the code here:

Code: Select all
/*
 *  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.apocalypse;

import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BecomesSubtypeTargetEffect;
import mage.cards.CardImpl;
import mage.cards.repository.CardRepository;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;

/**
 *
 * @author EvilGeek
 */
public class UnnaturalSelection extends CardImpl {

    public UnnaturalSelection(UUID ownerId) {
        super(ownerId, 32, "Unnatural Selection", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
        this.expansionSetCode = "APC";

        // {1}: Choose a creature type other than Wall. Target creature becomes that type until end of turn.
        Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UnnaturalSelectionEffect(), new GenericManaCost(1));
        ability.addTarget(new TargetCreaturePermanent());
        this.addAbility(ability);
    }

    public UnnaturalSelection(final UnnaturalSelection card) {
        super(card);
    }

    @Override
    public UnnaturalSelection copy() {
        return new UnnaturalSelection(this);
    }
}

class UnnaturalSelectionEffect extends OneShotEffect {

    public UnnaturalSelectionEffect() {
        super(Outcome.BoostCreature);
        staticText = "choose a creature type other than Wall. Target creature's type becomes that type until end of turn";
    }

    public UnnaturalSelectionEffect(final UnnaturalSelectionEffect effect) {
        super(effect);
    }

    @Override
    public boolean apply(Game game, Ability source) {
        Player player = game.getPlayer(source.getControllerId());
        MageObject sourceObject = game.getObject(source.getSourceId());
        if (player != null && sourceObject != null) {
            Choice typeChoice = new ChoiceImpl(true);
            typeChoice.setMessage("Choose creature type other than Wall");
            Set<String> types = CardRepository.instance.getCreatureTypes();
            types.remove("Wall");
            typeChoice.setChoices(types);
            while (!player.choose(Outcome.BoostCreature, typeChoice, game)) {
                if (!player.isInGame()) {
                    return false;
                }
            }
            game.informPlayers(sourceObject.getLogName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice());
            String chosenType = typeChoice.getChoice();
            if (chosenType != null && !chosenType.isEmpty()) {
                // ADD TYPE TO TARGET
                ContinuousEffect effect = new BecomesSubtypeTargetEffect(Duration.EndOfTurn, chosenType);
                effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source)));
                game.addEffect(effect, source);
                return true;
            }
        }
        return false;
    }

    @Override
    public Effect copy() {
        return new UnnaturalSelectionEffect(this);
    }

}
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby LevelX » 25 Jun 2015, 21:11

LoneFox wrote:Grab the Reins:

Both modes themselves work as expected, but for some reason they resolve in wrong order, meaning it's not possible to sacrifice the stolen creature, because it is still on opponent's side. I don't understand what is going on. Promise of Power is implemented in the same way, and there the modes resolve in correct order.
The key here is to use the effect.setApplyEffectsAfter() method.
Normally the continuous effects were applied after a spell resolves. But some spells are parted in dependant parts, so the effects have to be applied between the resolving of the effects.

Here's the working code:
Code: Select all
/*
 *  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.mirrodin;

import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.keyword.EntwineAbility;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreatureOrPlayer;
import mage.target.common.TargetCreaturePermanent;

/**
 *
 * @author LevelX2
 */
public class GrabTheReins extends CardImpl {

    public GrabTheReins(UUID ownerId) {
        super(ownerId, 95, "Grab the Reins", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{3}{R}");
        this.expansionSetCode = "MRD";

        // Choose one -
        this.getSpellAbility().getModes().setMinModes(1);
        this.getSpellAbility().getModes().setMaxModes(1);
        // Until end of turn, you gain control of target creature and it gains haste;
        this.getSpellAbility().addTarget(new TargetCreaturePermanent());
        Effect effect = new GainControlTargetEffect(Duration.EndOfTurn);
        effect.setApplyEffectsAfter();
        this.getSpellAbility().addEffect(effect);
        this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
        // Sacrifice a creature. Grab the Reins deals damage equal to that creature's power to target creature or player.
        Mode mode = new Mode();
        mode.getEffects().add(new GrabTheReinsEffect());
        mode.getTargets().add(new TargetCreatureOrPlayer());
        this.getSpellAbility().getModes().addMode(mode);

        // Entwine {2}{R}
        this.addAbility(new EntwineAbility("{2}{R}"));
    }

    public GrabTheReins(final GrabTheReins card) {
        super(card);
    }

    @Override
    public GrabTheReins copy() {
        return new GrabTheReins(this);
    }
}

class GrabTheReinsEffect extends OneShotEffect {

    public GrabTheReinsEffect() {
        super(Outcome.Damage);
        this.staticText = "Sacrifice a creature. {this} deals damage equal to that creature's power to target creature or player";
    }

    public GrabTheReinsEffect(final GrabTheReinsEffect effect) {
        super(effect);
    }

    @Override
    public GrabTheReinsEffect copy() {
        return new GrabTheReinsEffect(this);
    }

    @Override
    public boolean apply(Game game, Ability source) {
        Player controller = game.getPlayer(source.getControllerId());
        if (controller != null) {
            Target target = new TargetControlledCreaturePermanent();
            target.setNotTarget(true);
            if (controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) {
                Permanent creature = game.getPermanent(target.getFirstTarget());
                if (creature != null) {
                    if (creature.sacrifice(source.getSourceId(), game)) {
                        Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
                        if (targetCreature != null) {
                            targetCreature.damage(creature.getToughness().getValue(), source.getSourceId(), game, false, true);
                        } else {
                            Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
                            if (targetPlayer != null) {
                                targetPlayer.damage(creature.getToughness().getValue(), source.getSourceId(), game, false, true);
                            }
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }
}
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby EvilGeek » 25 Jun 2015, 21:14

LevelX wrote:I added the needed framework effect (not tested).
Ok, thanks. I'll try that and pull request asking for someone to test it.
EvilGeek
 
Posts: 8
Joined: 27 Nov 2014, 16:56
Has thanked: 0 time
Been thanked: 0 time

Re: Help implementing a card

Postby LevelX » 25 Jun 2015, 21:31

EvilGeek wrote:
LevelX wrote:I added the needed framework effect (not tested).
Ok, thanks. I'll try that and pull request asking for someone to test it.
I guess you can test it in your repository and IDE by merging all new commits in your repository.
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby EvilGeek » 25 Jun 2015, 21:47

LevelX wrote:
EvilGeek wrote:
LevelX wrote:I added the needed framework effect (not tested).
Ok, thanks. I'll try that and pull request asking for someone to test it.
I guess you can test it in your repository and IDE by merging all new commits in your repository.
I would but I'm not totally sure how to test, what with the configurations for maven and whatnot.
EvilGeek
 
Posts: 8
Joined: 27 Nov 2014, 16:56
Has thanked: 0 time
Been thanked: 0 time

Re: Help implementing a card

Postby fireshoes » 26 Jun 2015, 06:33

Working on Infernal Darkness. It is essentially the same as existing card Contamination, except Infernal Darkness should not reduce the amount of mana a land produces, only changes it to {B}. Ex. If Gaea's Cradle {G}{G}{G}, Infernal Darkness changes it to {B}{B}{B}, whereas Contamination changes it to just {B}.

This is the code Contamination uses:
Code: Select all
ManaEvent manaEvent = (ManaEvent) event;
Mana mana = manaEvent.getMana();
mana.setToMana(Mana.BlackMana);
return false;
I just need to know what to change so the quantity of mana produced is unaffected.
User avatar
fireshoes
 
Posts: 536
Joined: 20 Aug 2014, 03:51
Has thanked: 201 times
Been thanked: 49 times

Re: Help implementing a card

Postby LevelX » 26 Jun 2015, 08:28

fireshoes wrote:I just need to know what to change so the quantity of mana produced is unaffected.
Code: Select all
        ManaEvent manaEvent = (ManaEvent) event;
        Mana mana = manaEvent.getMana();
        mana.setToMana(BlackMana(mana.count()));
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby LevelX » 26 Jun 2015, 08:40

EvilGeek wrote:I would but I'm not totally sure how to test, what with the configurations for maven and whatnot.
So open a new thread here and tell us about your concrete problems so we can try to help.
What do you use, what have you already installed.
What does not work.
Normally you do the following steps:
1. Code the card and classes need to implement the card
2. Build the concerned projects
3. Start the server from IDE with argument "-testMode=true"
4. Start the client from IDE
5. Start a game with "Quick Start" button.
6. Add the cards needed for the test to the "Mage server/config/init.txt" file.
7. Push the smiley cheat button in the test game.
8. Use the cards to see if they work.

Alternate you can add a test case in the Mage Tests project and execute this test (always a good idea if using a new mechanic or implemnted a new complex card.

So tell me what point from (1-8) does not work?
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

Re: Help implementing a card

Postby fireshoes » 30 Jun 2015, 04:58

Working on Archangel of Tithes, using Norn's Annex and War Cadence as templates, but the effect requiring payment to attack or block is not occurring.
Code: Select all
public class ArchangelOfTithes extends CardImpl {

    public ArchangelOfTithes(UUID ownerId) {
        super(ownerId, 4, "Archangel of Tithes", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{1}{W}{W}{W}");
        this.expansionSetCode = "ORI";
        this.subtype.add("Angel");
        this.power = new MageInt(3);
        this.toughness = new MageInt(5);

        // Flying
        this.addAbility(FlyingAbility.getInstance());
       
        // As long as Archangel of Tithes is untapped, creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures.
        this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
                new ArchangelOfTithesAttackingReplacementEffect(),
                new InvertCondition(new SourceTappedCondition()),
                "creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures as long as {this} is untapped")));
       
        // As long as Archangel of Tithes is attacking, creatures can't block unless their controller pays {1} for each of those creatures.
        this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
                new ArchangelOfTithesBlockingReplacementEffect(),
                new SourceAttackingCondition(),
                "creatures can't block unless their controller pays {1} for each of those creatures as long as {this} is attacking")));
    }

    public ArchangelOfTithes(final ArchangelOfTithes card) {
        super(card);
    }

    @Override
    public ArchangelOfTithes copy() {
        return new ArchangelOfTithes(this);
    }
}

class ArchangelOfTithesAttackingReplacementEffect extends ReplacementEffectImpl {

    private static final String effectText = "Creatures can't attack you or a planeswalker you control unless their controller pays {1} for each creature he or she controls that's attacking you";

    ArchangelOfTithesAttackingReplacementEffect() {
        super(Duration.WhileOnBattlefield, Outcome.Benefit);
        staticText = effectText;
    }

    ArchangelOfTithesAttackingReplacementEffect(ArchangelOfTithesAttackingReplacementEffect effect) {
        super(effect);
    }
   
    @Override
    public boolean checksEventType(GameEvent event, Game game) {
        return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
    }
   
    @Override
    public boolean applies(GameEvent event, Ability source, Game game) {
        if (event.getTargetId().equals(source.getControllerId()) ) {
            return true;
        }
        // planeswalker
        Permanent permanent = game.getPermanent(event.getTargetId());
        return permanent != null && permanent.getControllerId().equals(source.getControllerId())
                && permanent.getCardType().contains(CardType.PLANESWALKER);
    }


    @Override
    public boolean replaceEvent(GameEvent event, Ability source, Game game) {
        Player player = game.getPlayer(event.getPlayerId());
        if (player != null) {
            ManaCostsImpl propagandaTax = new ManaCostsImpl("{1}");
            if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
                    player.chooseUse(Outcome.Benefit, "Pay {1} to declare attacker?", source, game)) {
                if (propagandaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }


    @Override
    public ArchangelOfTithesAttackingReplacementEffect copy() {
        return new ArchangelOfTithesAttackingReplacementEffect(this);
    }

}

class ArchangelOfTithesBlockingReplacementEffect extends ReplacementEffectImpl {

    ArchangelOfTithesBlockingReplacementEffect() {
        super(Duration.EndOfTurn, Outcome.Neutral);
        staticText = "Creatures can't block unless their controller pays {1} for each blocking creature he or she controls";
    }

    ArchangelOfTithesBlockingReplacementEffect(ArchangelOfTithesBlockingReplacementEffect effect) {
        super(effect);
    }

    @Override
    public boolean replaceEvent(GameEvent event, Ability source, Game game) {
        Player player = game.getPlayer(event.getPlayerId());
        if (player != null) {
            ManaCostsImpl cost = new ManaCostsImpl("{1}");
            if (cost.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
                player.chooseUse(Outcome.Benefit, new StringBuilder("Pay {1} to declare blocker?").toString(), source, game)) {
                if (cost.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean checksEventType(GameEvent event, Game game) {
        return event.getType() == GameEvent.EventType.DECLARE_BLOCKER;
    }
   
    @Override
    public boolean applies(GameEvent event, Ability source, Game game) {
        return true;
    }

    @Override
    public ArchangelOfTithesBlockingReplacementEffect copy() {
        return new ArchangelOfTithesBlockingReplacementEffect(this);
    }

}
User avatar
fireshoes
 
Posts: 536
Joined: 20 Aug 2014, 03:51
Has thanked: 201 times
Been thanked: 49 times

Re: Help implementing a card

Postby LevelX » 30 Jun 2015, 05:28

fireshoes wrote:Working on Archangel of Tithes, using Norn's Annex and War Cadence as templates, but the effect requiring payment to attack or block is not occurring.
Code: Select all
public class ArchangelOfTithes extends CardImpl {

    public ArchangelOfTithes(UUID ownerId) {
        super(ownerId, 4, "Archangel of Tithes", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{1}{W}{W}{W}");
        this.expansionSetCode = "ORI";
        this.subtype.add("Angel");
        this.power = new MageInt(3);
        this.toughness = new MageInt(5);

        // Flying
        this.addAbility(FlyingAbility.getInstance());
       
        // As long as Archangel of Tithes is untapped, creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures.
        this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
                new ArchangelOfTithesAttackingReplacementEffect(),
                new InvertCondition(new SourceTappedCondition()),
                "creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures as long as {this} is untapped")));
       
        // As long as Archangel of Tithes is attacking, creatures can't block unless their controller pays {1} for each of those creatures.
        this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
                new ArchangelOfTithesBlockingReplacementEffect(),
                new SourceAttackingCondition(),
                "creatures can't block unless their controller pays {1} for each of those creatures as long as {this} is attacking")));
    }

    public ArchangelOfTithes(final ArchangelOfTithes card) {
        super(card);
    }

    @Override
    public ArchangelOfTithes copy() {
        return new ArchangelOfTithes(this);
    }
}

class ArchangelOfTithesAttackingReplacementEffect extends ReplacementEffectImpl {

    private static final String effectText = "Creatures can't attack you or a planeswalker you control unless their controller pays {1} for each creature he or she controls that's attacking you";

    ArchangelOfTithesAttackingReplacementEffect() {
        super(Duration.WhileOnBattlefield, Outcome.Benefit);
        staticText = effectText;
    }

    ArchangelOfTithesAttackingReplacementEffect(ArchangelOfTithesAttackingReplacementEffect effect) {
        super(effect);
    }
   
    @Override
    public boolean checksEventType(GameEvent event, Game game) {
        return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
    }
   
    @Override
    public boolean applies(GameEvent event, Ability source, Game game) {
        if (event.getTargetId().equals(source.getControllerId()) ) {
            return true;
        }
        // planeswalker
        Permanent permanent = game.getPermanent(event.getTargetId());
        return permanent != null && permanent.getControllerId().equals(source.getControllerId())
                && permanent.getCardType().contains(CardType.PLANESWALKER);
    }


    @Override
    public boolean replaceEvent(GameEvent event, Ability source, Game game) {
        Player player = game.getPlayer(event.getPlayerId());
        if (player != null) {
            ManaCostsImpl propagandaTax = new ManaCostsImpl("{1}");
            if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
                    player.chooseUse(Outcome.Benefit, "Pay {1} to declare attacker?", source, game)) {
                if (propagandaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }


    @Override
    public ArchangelOfTithesAttackingReplacementEffect copy() {
        return new ArchangelOfTithesAttackingReplacementEffect(this);
    }

}

class ArchangelOfTithesBlockingReplacementEffect extends ReplacementEffectImpl {

    ArchangelOfTithesBlockingReplacementEffect() {
        super(Duration.EndOfTurn, Outcome.Neutral);
        staticText = "Creatures can't block unless their controller pays {1} for each blocking creature he or she controls";
    }

    ArchangelOfTithesBlockingReplacementEffect(ArchangelOfTithesBlockingReplacementEffect effect) {
        super(effect);
    }

    @Override
    public boolean replaceEvent(GameEvent event, Ability source, Game game) {
        Player player = game.getPlayer(event.getPlayerId());
        if (player != null) {
            ManaCostsImpl cost = new ManaCostsImpl("{1}");
            if (cost.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
                player.chooseUse(Outcome.Benefit, new StringBuilder("Pay {1} to declare blocker?").toString(), source, game)) {
                if (cost.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean checksEventType(GameEvent event, Game game) {
        return event.getType() == GameEvent.EventType.DECLARE_BLOCKER;
    }
   
    @Override
    public boolean applies(GameEvent event, Ability source, Game game) {
        return true;
    }

    @Override
    public ArchangelOfTithesBlockingReplacementEffect copy() {
        return new ArchangelOfTithesBlockingReplacementEffect(this);
    }

}
You have to use ConditionalReplacementEffect.
User avatar
LevelX
DEVELOPER
 
Posts: 1677
Joined: 08 Dec 2011, 15:08
Has thanked: 174 times
Been thanked: 374 times

PreviousNext

Return to Developers Talk

Who is online

Users browsing this forum: No registered users and 2 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 2 users online :: 0 registered, 0 hidden and 2 guests (based on users active over the past 10 minutes)
Most users ever online was 9298 on 10 Oct 2025, 12:54

Users browsing this forum: No registered users and 2 guests

Login Form