It is currently 19 Jul 2025, 07:51
   
Text Size

Adding new cards with Groovy

Moderators: ubeefx, beholder, melvin, ShawnieBoy, Lodici, CCGHQ Admins

Re: Adding new cards with Groovy

Postby ShawnieBoy » 01 Mar 2014, 18:38

I've submitted a test scenario - though I was only half-joking :) TestReaperKing
User avatar
ShawnieBoy
Programmer
 
Posts: 601
Joined: 02 Apr 2012, 22:42
Location: UK
Has thanked: 80 times
Been thanked: 50 times

Re: Adding new cards with Groovy

Postby Lodici » 02 Mar 2014, 06:48

ShawnieBoy wrote:I've submitted a test scenario - though I was only half-joking :) TestReaperKing
Thanks. Interesting, it even wipes out the player info! :D
Untitled.png

Is there any reason why, in extreme cases like this, you could not just prompt the player to pay 10 and leave it for them to decide instead of offering all possible options? As they tap the prompt would count down until the required mana count has been reached. Alternatively, I am sure we could probably add a JScrollPane or even use something like a JList instead of multiple JButtons.
User avatar
Lodici
Programmer
 
Posts: 399
Joined: 13 Oct 2013, 09:44
Has thanked: 29 times
Been thanked: 71 times

Re: Adding new cards with Groovy

Postby ShawnieBoy » 02 Mar 2014, 07:47

The total mana cost for Reaper King can vary from 5 -> 10. It's the same problem we had with Phyrexian Mana, unable to give an extra prompt to pay mana or life for each step, but this time 2 colorless mana or 1 colored.
User avatar
ShawnieBoy
Programmer
 
Posts: 601
Joined: 02 Apr 2012, 22:42
Location: UK
Has thanked: 80 times
Been thanked: 50 times

Re: Adding new cards with Groovy

Postby melvin » 02 Mar 2014, 09:46

Another card inspired by the recent Pro Tour BNG, where I noticed players cast the card from graveyard immediately after playing Snapcaster Mage. This reminded me that the Varolz trick can be used to implement Snapcaster Mage.

Image

Magarena/scripts/Snapcaster_Mage.txt
Code: Select all
name=Snapcaster Mage
url=http://magiccards.info/isd/en/78.html
image=http://mtgimage.com/card/snapcaster%20mage.jpg
value=3.723
rarity=R
type=Creature
subtype=Human,Wizard
cost={1}{U}
pt=2/1
ability=flash
timing=main
requires_groovy_code
Magarena/scripts/Snapcaster_Mage.groovy
Code: Select all
def A_PAYABLE_INSTANT_OR_SORCERY_CARD_FROM_YOUR_GRAVEYARD = new MagicTargetChoice(
    MagicTargetFilter.PAYABLE_INSTANT_OR_SORCERY_FROM_GRAVEYARD,
    "a instant or sorcery card from your graveyard"
);

[
    new MagicWhenComesIntoPlayTrigger() {
        @Override
        public MagicEvent executeTrigger(final MagicGame game, final MagicPermanent permanent, final MagicPayedCost payedCost) {
            return new MagicEvent(
                permanent,
                new MagicMayChoice(
                    A_PAYABLE_INSTANT_OR_SORCERY_CARD_FROM_YOUR_GRAVEYARD
                ),
                MagicGraveyardTargetPicker.PutOntoBattlefield,
                this,
                "PN may\$ cast target instant or sorcery card\$ from his or her graveyard, then exile it."
            );
        }
        @Override
        public void executeEvent(final MagicGame game, final MagicEvent event) {
            if (event.isYes()) {
                event.processTargetCard(game, {
                    final MagicCard card ->
                    game.addEvent(new MagicPayManaCostEvent(card,card.getCost()));
                    game.addEvent(new MagicEvent(
                        card,
                        {
                            final MagicGame G, final MagicEvent E ->
                            G.doAction(new MagicRemoveCardAction(E.getCard(),MagicLocationType.Graveyard));
                            final MagicCardOnStack cardOnStack=new MagicCardOnStack(card,event.getPlayer(),game.getPayedCost());
                            cardOnStack.setMoveLocation(MagicLocationType.Exile);
                            game.doAction(new MagicPutItemOnStackAction(cardOnStack));
                        },
                        "Cast SN."
                    ));
                });
            }
        }
    }
]
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby hong yie » 02 Mar 2014, 13:10

is this mean all flashback cards is supported now? :)
User avatar
hong yie
Programmer
 
Posts: 216
Joined: 10 Mar 2013, 06:44
Location: Jakarta
Has thanked: 75 times
Been thanked: 9 times

Re: Adding new cards with Groovy

Postby melvin » 02 Mar 2014, 13:36

No, technically the card didn't gain flashback. Snapcaster Mage is implemented as if it has the ability: When Snapcaster Mage enters the battlefield, you may cast target instant or sorcery card from your graveyard by paying its mana cost, then exile it.
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby Lodici » 02 Mar 2014, 17:33

ShawnieBoy wrote:The total mana cost for Reaper King can vary from 5 -> 10. It's the same problem we had with Phyrexian Mana, unable to give an extra prompt to pay mana or life for each step, but this time 2 colorless mana or 1 colored.
How about something like...?
Untitled.png
User avatar
Lodici
Programmer
 
Posts: 399
Joined: 13 Oct 2013, 09:44
Has thanked: 29 times
Been thanked: 71 times

Re: Adding new cards with Groovy

Postby ShawnieBoy » 02 Mar 2014, 19:07

Cool :) - It was more the coding side of things I think though - The normal prompt for mana would work for {2/W} etc if it could accept and highlight all colorless mana sources and relevant color sources. If the colored source was selected, it would then move to the next mana as normal (for Reaper King, {2/U}), otherwise wait for another colorless source to be chosen. The multi-button approach was only used as it's being used for Phyrexian mana.

This would be how it would look. (ie. not different at all)
Payment Hybrid .png
Colorless Hybrid Payment Prompt

Phyrexian mana can't use the normal mana prompt, as there's nowhere to select 'Pay 2 life', so that's why the button prompt is being used. So something like this would be perfect if the code behind it could work. (Assuming that in this example, black mana sources are being highlighted on the battlefield. So a choice between the button or mana, if mana is possible, if not then no prompt and 2 life is paid right away.)
payment phyrexian.png
Phyrexian Payment Prompt
User avatar
ShawnieBoy
Programmer
 
Posts: 601
Joined: 02 Apr 2012, 22:42
Location: UK
Has thanked: 80 times
Been thanked: 50 times

Re: Adding new cards with Groovy

Postby Lodici » 02 Mar 2014, 20:32

I have updated the game prompt so that it will show a scrollbar if required which means you can at least access all the options for Reaper King although it is not very aesthetic (http://bitbucket.org/lodici/magarena/co ... 507510bee8).
This might also require the fix for issue 494 (https://bitbucket.org/lodici/magarena/c ... e73ff6a201).
Attachments
Untitled.png
User avatar
Lodici
Programmer
 
Posts: 399
Joined: 13 Oct 2013, 09:44
Has thanked: 29 times
Been thanked: 71 times

Re: Adding new cards with Groovy

Postby melvin » 09 Mar 2014, 10:46

Image

Magarena/scripts/Birthing_Pod.txt
Code: Select all
name=Birthing Pod
url=http://magiccards.info/query?q=%21birthing%20pod
image=http://mtgimage.com/card/birthing%20pod.jpg
value=4.588
rarity=R
type=Artifact
cost={3}{P/G}
ability=alt cost {3}, Pay 2 life named Pay 2 life
timing=artifact
requires_groovy_code
Magarena/scripts/Birthing_Pod.groovy
Code: Select all
def action = {
    final MagicGame game, final MagicEvent event ->
    final int cmc = event.getRefInt();
    final MagicTargetFilter filter = new MagicTargetFilter.MagicCMCCardFilter(
        MagicTargetFilter.Factory.card(MagicTargetType.Library, MagicType.Creature),
        MagicTargetFilter.Operator.EQUAL,
        cmc
    );
    final MagicTargetChoice choice = new MagicTargetChoice(
        filter,
        "a creature card with converted mana cost ${cmc} from your library"
    );
    game.addEvent(new MagicSearchOntoBattlefieldEvent(
        event,
        choice
    ));
}

def event = {
    final MagicPermanent source, final MagicPayedCost payedCost ->
    // canPlay check uses NO_COST
    if (payedCost == MagicPayedCost.NO_COST) {
        return MagicEvent.NONE;
    }
    final int cmc = ((MagicPermanent)payedCost.getTarget()).getConvertedCost() + 1;
    return new MagicEvent(
        source,
        cmc,
        action,
        "PN searches PN's library for a creature card with converted mana cost RN, put that card onto the battlefield, then shuffle your library."
    );
}

[
    new MagicPermanentActivation(
        [MagicCondition.SORCERY_CONDITION],
        new MagicActivationHints(MagicTiming.Main),
        "Search"
    ) {

        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [
                new MagicPayManaCostEvent(source, "{1}{P/G}"),
                new MagicTapEvent(source),
                new MagicSacrificePermanentEvent(source, MagicTargetChoice.SACRIFICE_CREATURE),
            ];
        }

        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
            return event(source, payedCost);
        }
    },
    new MagicPermanentActivation(
        [MagicCondition.SORCERY_CONDITION],
        new MagicActivationHints(MagicTiming.Main),
        "Pay 2 life"
    ) {

        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [
                new MagicPayManaCostEvent(source, "{1}"),
                new MagicPayLifeEvent(source, 2),
                new MagicTapEvent(source),
                new MagicSacrificePermanentEvent(source, MagicTargetChoice.SACRIFICE_CREATURE),
            ];
        }
   
        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
            return event(source, payedCost);
        }
    }
]
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby ShawnieBoy » 09 Mar 2014, 12:43

Nice one! :D

Just another idea - most non-mana costs in CostEvent are essentially effects. Could linking them to RuleEventAction help prevent having to duplicate entries (eg. The BounceBasicLand, BounceCreature, BounceLand, BounceSelf entries)
User avatar
ShawnieBoy
Programmer
 
Posts: 601
Joined: 02 Apr 2012, 22:42
Location: UK
Has thanked: 80 times
Been thanked: 50 times

Re: Adding new cards with Groovy

Postby melvin » 09 Mar 2014, 13:10

Yes, that would work. At first, it seems that costs are simpler than effects, so I made them separate. As we add more, it gets a bit reptitive, the duplication that can be eliminated if MagicCostEvent is merged into MagicRuleEventAction.
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby melvin » 10 Mar 2014, 12:45

Image

Magarena/scripts/Detention_Sphere.txt
Code: Select all
name=Detention Sphere
url=http://magiccards.info/query?q=%21detention%20sphere
image=http://mtgimage.com/card/detention%20sphere.jpg
value=4.000
rarity=R
type=Enchantment
cost={1}{W}{U}
ability=leaves return exile
timing=enchantment
requires_groovy_code
Magarena/scripts/Detention_Sphere.groovy
Code: Select all
def filter = new MagicPermanentFilterImpl() {
    public boolean accept(final MagicGame game,final MagicPlayer player,final MagicPermanent target) {
        return target.isLand() == false && target.getName().equals("Detention Sphere") == false;
    }
};

def choice = new MagicTargetChoice(filter, "target nonland permanent not named Detention Sphere");

[
    new MagicWhenComesIntoPlayTrigger() {
        @Override
        public MagicEvent executeTrigger(final MagicGame game,final MagicPermanent permanent, final MagicPayedCost payedCost) {
            return new MagicEvent(
                permanent,
                choice,
                MagicExileTargetPicker.create(),
                this,
                "Exile target nonland permanent\$ not named Detention Sphere and all other permanents with the same name as that permanent."
            );
        }
        @Override
        public void executeEvent(final MagicGame game, final MagicEvent event) {
            event.processTargetPermanent(game, {
                final MagicPermanent permanent ->
                final Collection<MagicPermanent> targets = game.filterPermanents(
                    event.getPlayer(),
                    new MagicTargetFilter.NameTargetFilter(permanent.getName())
                );
                for (final MagicPermanent target : targets) {
                    game.doAction(new MagicExileUntilThisLeavesPlayAction(
                        event.getPermanent(),
                        target
                    ));
                }
            });
        }
    }
]
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby melvin » 18 Mar 2014, 14:13

Image

Magarena/scripts/Spellskite.txt
Code: Select all
name=Spellskite
url=http://magiccards.info/query?q=%21spellskite
image=http://mtgimage.com/card/spellskite.jpg
value=3.723
rarity=R
type=Artifact,Creature
subtype=Horror
cost={2}
pt=0/4
timing=main
requires_groovy_code
Magarena/scripts/Spellskite.groovy
Code: Select all
def action = {
    final MagicGame game, final MagicEvent event ->
    event.processTargetItemOnStack(game, {
        final MagicItemOnStack item ->
        game.doAction(new MagicChangeTargetAction(item, event.getPermanent()));
    });
}

def event = {
    final MagicPermanent source ->
    return new MagicEvent(
        source,
        new MagicTargetChoice(MagicTargetFilter.SPELL_OR_ABILITY_WITH_TARGET, MagicTargetHint.Negative, "target spell or ability"),
        action,
        "Change the target of target spell or ability\$ to SN."
    );
}

[
    new MagicPermanentActivation(
        new MagicActivationHints(MagicTiming.Spell),
        "Retarget"
    ) {

        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [new MagicPayManaCostEvent(source, "{U}")];
        }

        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source,final MagicPayedCost payedCost) {
            return event(source);
        }
    },
    new MagicPermanentActivation(
        new MagicActivationHints(MagicTiming.Spell),
        "Pay 2 life"
    ) {

        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [new MagicPayLifeEvent(source, 2)];
        }

        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source,final MagicPayedCost payedCost) {
            return event(source);
        }
    }
]
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

Re: Adding new cards with Groovy

Postby ShawnieBoy » 18 Mar 2014, 17:57

Nice!

Another thought, looking at Birthing Pod again - Transmute should be implementable using similar mechanics.
User avatar
ShawnieBoy
Programmer
 
Posts: 601
Joined: 02 Apr 2012, 22:42
Location: UK
Has thanked: 80 times
Been thanked: 50 times

PreviousNext

Return to Magarena

Who is online

Users browsing this forum: No registered users and 1 guest

Main Menu

User Menu

Our Partners


Who is online

In total there is 1 user online :: 0 registered, 0 hidden and 1 guest (based on users active over the past 10 minutes)
Most users ever online was 7303 on 15 Jul 2025, 20:46

Users browsing this forum: No registered users and 1 guest

Login Form