Page 26 of 28

Re: Adding new cards with Groovy

PostPosted: 23 Sep 2014, 12:51
by melvin
Agree, running untrusted code safely is tough. In that case, does it still make sense to merge the changeset in your repo for running card scripts?

Re: Adding new cards with Groovy

PostPosted: 23 Sep 2014, 14:01
by mike
I can still check scripts that run without groovy. The changeset also implements error reporting on firemind which should help debug duels through the web interface.

In short: yes, a merge still makes sense.

Re: Adding new cards with Groovy

PostPosted: 24 Sep 2014, 00:53
by melvin
Sure, the changeset is merged. I also pushed a small fix to make the code more idiomatic in https://code.google.com/p/magarena/sour ... c69078a89a

Re: Adding new cards with Groovy

PostPosted: 24 Sep 2014, 20:24
by PalladiaMors
Guys, I can't really follow the conversation here, but rather than programming ways to automatically detect if a script works, why don't you just include a warning for people in the submissions page, something like "Before submitting a script, make sure you playtest it to see if it works correctly. If you don't know how to do that, check the Magarena forums for information". In my very humble opinion, that looks simpler and might wield good results...

Re: Adding new cards with Groovy

PostPosted: 25 Sep 2014, 01:35
by hong yie
can't submit to firemind.ch,
so i put it here. :)

Gorgon_Recluse.txt
Code: Select all
name=Gorgon Recluse
image=http://mtgimage.com/card/gorgon%20recluse.jpg
value=2.500
rarity=C
type=Creature
subtype=Gorgon
cost={3}{B}{B}
pt=2/4
ability=Madness {B}{B}
timing=main
requires_groovy_code=Deathgazer
oracle=Whenever Gorgon Recluse blocks or becomes blocked by a nonblack creature, destroy that creature at end of combat. Madness {B}{B}
Siege_Rhino.txt
Code: Select all
name=Siege Rhino
image=http://magiccards.info/scans/en/ktk/200.jpg
value=2.500
rarity=R
type=Creature
subtype=Rhino
cost={1}{W}{B}{G}
pt=4/5
ability=Trample; When SN enters the battlefield, each opponent loses 3 life and you gain 3 life.
timing=main
oracle=Trample. When Siege Rhino enters the battlefield, each opponent loses 3 life and you gain 3 life.

Re: Adding new cards with Groovy

PostPosted: 25 Sep 2014, 05:12
by melvin
Thanks, added Gorgon Recluse in https://code.google.com/p/magarena/sour ... 095697e769

Siege Rhino's effect can't be parsed as is, you'll get an error when the game loads it. It needs to be rewritten as multiple effects separated by ~, i.e. "When SN enters the battlefield, each opponent loses 3 life.~You gain 3 life." See https://code.google.com/p/magarena/sour ... 07cd09f48a

Re: Adding new cards with Groovy

PostPosted: 23 Oct 2014, 18:05
by jerichopumpkin
I was trying to add Doran, the Siege Tower, and everything is smooth (no crashes, the game runs fine) except it doesn't work...
Code: Select all
[
    new MagicIfDamageWouldBeDealtTrigger(MagicTrigger.INCREASE_DAMAGE) {
        @Override
        public MagicEvent executeTrigger(final MagicGame game,final MagicPermanent permanent,final MagicDamage damage) {
            final MagicSource source = damage.getSource();
            if (damage.isCombat() && source.isCreature()) {
                // Generates no event or action.
                damage.setAmount(source.getCardDefinition().getCardToughness());
            }
            return MagicEvent.NONE;
        }
    }
]
someone can help me with this one? I don't see what I'm doing wrong...

edit: at first I tried with MagicTrigger.REPLACE_DAMAGE, but there was no difference

Re: Adding new cards with Groovy

PostPosted: 23 Oct 2014, 19:51
by mike
someone can help me with this one? I don't see what I'm doing wrong...
I took this as an opportunity to explore the magarena source a little.

Unfortunately my conclusion is that there is no easy way to do this.

In MagicCombatDamageAction.java on line 74 I found this

Code: Select all
if (power>0 && !attacker.hasState(MagicPermanentState.NoCombatDamage))
Which means a MagicDealDamageAction is never created and hence no MagicIfDamageWouldBeDealtTrigger will ever be invoked.

If I might propose a solution for this: How about replacing power=attacker.getPower() with power=attacker.getCombatPower() which is by default getPower but may be overrwritten for cases like this? This is assuming that attacker.getPower may be overwritten from within the groovy script.

Re: Adding new cards with Groovy

PostPosted: 23 Oct 2014, 21:52
by jerichopumpkin
mike wrote:
In MagicCombatDamageAction.java on line 74 I found this

Code: Select all
if (power>0 && !attacker.hasState(MagicPermanentState.NoCombatDamage))
Which means a MagicDealDamageAction is never created and hence no MagicIfDamageWouldBeDealtTrigger will ever be invoked.

If I might propose a solution for this: How about replacing power=attacker.getPower() with power=attacker.getCombatPower() which is by default getPower but may be overrwritten for cases like this? This is assuming that attacker.getPower may be overwritten from within the groovy script.
I took a quick glance myself after reading this, and also on line 61 the same check is done for blockers.
I thought the calculations to distribute damage where done after the trigger, but I was dead wrong (thinking about it, it should have been obvious from the start).
Not sure about your idea, there should also be a new MagicStatic to change the value returned by getCombatPower().
For now I will move Doran back to the missing folder, and see if I can put togheter some other cards

Re: Adding new cards with Groovy

PostPosted: 24 Oct 2014, 02:29
by melvin
The checks are there for rule 119.8
119.8. If a source would deal 0 damage, it does not deal damage at all. That means abilities that trigger on damage being dealt won’t trigger. It also means that replacement effects that would increase the damage dealt by that source, or would have that source deal that damage to a different object or player, have no event to replace, so they have no effect.
Adding getCombatPower and a MagicStatic to modify the combat power value is one possible way, but introduces additional complexity such as additional state in MagicPermanent for combat power which would have to be initialized and managed properly. What others cards would be enabled from such a feature besides Doran?

Re: Adding new cards with Groovy

PostPosted: 24 Oct 2014, 06:58
by jerichopumpkin
melvin wrote:The checks are there for rule 119.8
119.8. If a source would deal 0 damage, it does not deal damage at all. That means abilities that trigger on damage being dealt won’t trigger. It also means that replacement effects that would increase the damage dealt by that source, or would have that source deal that damage to a different object or player, have no event to replace, so they have no effect.
Adding getCombatPower and a MagicStatic to modify the combat power value is one possible way, but introduces additional complexity such as additional state in MagicPermanent for combat power which would have to be initialized and managed properly. What others cards would be enabled from such a feature besides Doran?
I fear the answer is: "none". That's a shame, I really love Doran, but it doesn't make sense to add all this code for a single card.

Re: Adding new cards with Groovy

PostPosted: 24 Oct 2014, 07:27
by hong yie
I fear the answer is: "none". That's a shame, I really love Doran, but it doesn't make sense to add all this code for a single card.
it does make sense if we want to achieve 100% playable cards in MtG. Just put it at lower priority. :)

Re: Adding new cards with Groovy

PostPosted: 02 Nov 2014, 01:53
by melvin
Image

Magarena/scripts/Gargantuan_Gorilla.txt
Code: Select all
name=Gargantuan Gorilla
image=http://mtgimage.com/card/gargantuan%20gorilla.jpg
value=2.500
rarity=R
type=Creature
subtype=Ape
cost={4}{G}{G}{G}
pt=7/7
timing=main
requires_groovy_code
oracle=At the beginning of your upkeep, you may sacrifice a Forest. If you sacrifice a snow Forest this way, Gargantuan Gorilla gains trample until end of turn. If you don't sacrifice a Forest, sacrifice Gargantuan Gorilla and it deals 7 damage to you. {T}: Gargantuan Gorilla deals damage equal to its power to another target creature. That creature deals damage equal to its power to Gargantuan Gorilla.
Magarena/scripts/Gargantuan_Gorilla.groovy
Code: Select all
def SAC_ACTION = {
    final MagicGame game, final MagicEvent event ->
    event.processTargetPermanent(game, {
        game.doAction(new MagicSacrificeAction(it));
        if (it.hasType(MagicType.Snow)) {
            game.doAction(new MagicGainAbilityAction(event.getPermanent(),MagicAbility.Trample));
        }
    })
}

[
    new MagicAtYourUpkeepTrigger() {
        @Override
        public MagicEvent executeTrigger(final MagicGame game,final MagicPermanent permanent,final MagicPlayer upkeepPlayer) {
            return new MagicEvent(
                permanent,
                new MagicMayChoice("Sacrifice a Forest?"),
                this,
                "PN may\$ sacrifice a Forest. " +
                "If PN sacrifices a snow Forest this way, SN gains trample until end of turn. " +
                "If PN doesn't sacrifice a Forest, sacrifice SN and it deals 7 damage to you."
            );
        }

        @Override
        public void executeEvent(final MagicGame game, final MagicEvent event) {
            final MagicPermanent SN = event.getPermanent();
            final MagicPlayer PN = event.getPlayer();
            final MagicEvent sac = new MagicEvent(
                SN,
                PN,
                MagicTargetChoice.SACRIFICE_FOREST,
                MagicSacrificeTargetPicker.create(),
                SAC_ACTION,
                "Choose a Forest to sacrifice\$."
            );
            if (event.isYes() && PN.controlsPermanent(MagicSubType.Forest)) {
                game.addEvent(sac);
            } else {
                game.doAction(new MagicSacrificeAction(SN));
                game.doAction(new MagicDealDamageAction(SN, PN, 7));
            }
        }
    },
    new MagicPermanentActivation(
        new MagicActivationHints(MagicTiming.Removal),
        "Damage"
    ) {

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

        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
            return new MagicEvent(
                source,
                MagicTargetChoice.NegOther("target creature", source),
                new MagicDamageTargetPicker(source.getPower()),
                this,
                "SN deals damage equal to its power to another target creature. " +
                "That creature deals damage equal to its power to SN."
            );
        }

        @Override
        public void executeEvent(final MagicGame game, final MagicEvent event) {
            event.processTargetPermanent(game, {
                game.doAction(new MagicDealDamageAction(
                    event.getPermanent(),
                    it,
                    event.getPermanent().getPower()
                ));
                game.doAction(new MagicDealDamageAction(
                    it,
                    event.getPermanent(),
                    it.getPower()
                ));
            });
        }
    }
]

Re: Adding new cards with Groovy

PostPosted: 02 Nov 2014, 14:10
by PalladiaMors
Trying to do Ebon Praetor, but I can't find the name of the "activate only once each turn" condition. I know it's in, there's plenty of cards with it, just not in groovy form. Can someone please tell me the right name?

Code: Select all
[
    new MagicPermanentActivation(
        [MagicCondition.YOUR_UPKEEP_CONDITION, MagicCondition.NO_MORE_THAN_ONCE_CONDITION],
        new MagicActivationHints(MagicTiming.Pump),
        "Sacrifice"
    ) {
        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [new MagicSacrificePermanentEvent(source,MagicTargetChoice.SACRIFICE_CREATURE)];
        }

        @Override
        public MagicEvent getPermanentEvent(final MagicPermanent source, final MagicPayedCost payedCost) {
            return new MagicEvent(
                source,
                payedCost.getTarget(),
                this,
                "Remove a -2/-2 counter from SN. " +
                "If the sacrificed creature was a Thrull, put a +1/+0 counter on SN."
            );
        }

        @Override
        public void executeEvent(final MagicGame game, final MagicEvent event) {
            final MagicPermanent sacrificed = event.getRefPermanent();
            new MagicRemoveCounterEvent(
            event.getPermanent(),
            MagicCounterType.MinusTwo,
            1
            );
            if (sacrificed.hasSubType(MagicSubType.Thrull)) {
                game.doAction(new MagicChangeCountersAction(
                event.getPermanent(),
                MagicCounterType.PlusOnePlusZero,
                1
                ));
            }
        }
    }
]

Re: Adding new cards with Groovy

PostPosted: 03 Nov 2014, 00:35
by melvin
Add "new MagicPlayAbilityEvent(source)" to getCostEvent for activate at most once per turn.

For example,
Code: Select all
        @Override
        public Iterable<MagicEvent> getCostEvent(final MagicPermanent source) {
            return [
                new MagicSacrificePermanentEvent(source,MagicTargetChoice.SACRIFICE_CREATURE),
                new MagicPlayAbilityEvent(source)
            ];
        }