It is currently 20 Apr 2024, 04:08
   
Text Size

Adding new cards with Groovy

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

Re: Adding new cards with Groovy

Postby melvin » 23 Sep 2014, 12:51

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?
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 mike » 23 Sep 2014, 14:01

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.
User avatar
mike
Programmer
 
Posts: 128
Joined: 05 Jul 2013, 17:00
Has thanked: 0 time
Been thanked: 29 times

Re: Adding new cards with Groovy

Postby melvin » 24 Sep 2014, 00:53

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
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 PalladiaMors » 24 Sep 2014, 20:24

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...
PalladiaMors
 
Posts: 343
Joined: 12 Jul 2014, 17:40
Has thanked: 36 times
Been thanked: 22 times

Re: Adding new cards with Groovy

Postby hong yie » 25 Sep 2014, 01:35

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.
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 » 25 Sep 2014, 05:12

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
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 jerichopumpkin » 23 Oct 2014, 18:05

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
jerichopumpkin
 
Posts: 212
Joined: 12 Sep 2013, 11:21
Has thanked: 19 times
Been thanked: 13 times

Re: Adding new cards with Groovy

Postby mike » 23 Oct 2014, 19:51

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.
User avatar
mike
Programmer
 
Posts: 128
Joined: 05 Jul 2013, 17:00
Has thanked: 0 time
Been thanked: 29 times

Re: Adding new cards with Groovy

Postby jerichopumpkin » 23 Oct 2014, 21:52

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
jerichopumpkin
 
Posts: 212
Joined: 12 Sep 2013, 11:21
Has thanked: 19 times
Been thanked: 13 times

Re: Adding new cards with Groovy

Postby melvin » 24 Oct 2014, 02:29

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?
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 jerichopumpkin » 24 Oct 2014, 06:58

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.
jerichopumpkin
 
Posts: 212
Joined: 12 Sep 2013, 11:21
Has thanked: 19 times
Been thanked: 13 times

Re: Adding new cards with Groovy

Postby hong yie » 24 Oct 2014, 07:27

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. :)
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 Nov 2014, 01:53

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()
                ));
            });
        }
    }
]
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 PalladiaMors » 02 Nov 2014, 14:10

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
                ));
            }
        }
    }
]
PalladiaMors
 
Posts: 343
Joined: 12 Jul 2014, 17:40
Has thanked: 36 times
Been thanked: 22 times

Re: Adding new cards with Groovy

Postby melvin » 03 Nov 2014, 00:35

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)
            ];
        }
User avatar
melvin
AI Programmer
 
Posts: 1062
Joined: 21 Mar 2010, 12:26
Location: Singapore
Has thanked: 36 times
Been thanked: 459 times

PreviousNext

Return to Magarena

Who is online

Users browsing this forum: No registered users and 47 guests


Who is online

In total there are 47 users online :: 0 registered, 0 hidden and 47 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 47 guests

Login Form