It is currently 11 Sep 2025, 21:41
   
Text Size

Groovy - script language that runs on JVM

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Groovy - script language that runs on JVM

Postby mtgrares » 14 Dec 2009, 18:29

While reading the blog about MagicEngine, the author mentions that he is using Groovy. Groovy is a dynamic language that lets you do cool stuff like generate code and compile it on the fly. It looks interesting. Below is taken from the Groovy home page.

Groovy...
* is an agile and dynamic language for the Java Virtual Machine
* builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk
* makes modern programming features available to Java developers with almost-zero learning curve
* supports Domain-Specific Languages and other compact syntax so your code becomes easy to read and maintain
* makes writing shell and build scripts easy with its powerful processing primitives, OO abilities and an Ant DSL
* increases developer productivity by reducing scaffolding code when developing web, GUI, database or console applications
* simplifies testing by supporting unit testing and mocking out-of-the-box
* seamlessly integrates with all existing Java objects and libraries
* compiles straight to Java bytecode so you can use it anywhere you can use Java
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Groovy - script language that runs on JVM

Postby Arch » 14 Dec 2009, 22:29

If you haven't gone outside of the Java/C++ world I can attest to there being a lot of cool stuff out there. And if you're interested I would probably suggest any of the "scripting" languages available. (Python, Groovy, Ruby, Perl...) Dynamic typing is FUN!

I would however also like to warn about the number of buzz-words thrown around in the cut-and-paste above...those things can kill you.
User avatar
Arch
Programmer
 
Posts: 206
Joined: 04 Jul 2009, 09:35
Has thanked: 0 time
Been thanked: 15 times

Re: Groovy - script language that runs on JVM

Postby Rob Cashwalker » 15 Dec 2009, 04:04

Magic Wars shares some codebase with Forge, in some of the key areas - the SpellAbility object, and then exposes them almost directly using Groovy. I'm sure it's no small feat and I know I wouldn't even try.

Yet, left to my own devices, I am happy to reinvent the wheel with my complex keyword syntax.

That's one con - Groovy makes complex cards easy to add, but simple cards become more complex. For example, Shock - In Forge it is simply coded as "spDamageTgtCP:2" but the Groovy code is much longer. The difference, is that by packing so much information into my syntax, produces a much longer code implementation than Shock was to begin with in pure Forge java code.

Also keep in mind that Forge code needs to provide for both the rules, game action and AI of any given effect. MagicWars' Groovy code only needs to describe the action, much of the rules are handled internally, and there's no AI (yet?)
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: Groovy - script language that runs on JVM

Postby nantuko84 » 16 Dec 2009, 12:01

That's one con - Groovy makes complex cards easy to add, but simple cards become more complex. For example, Shock - In Forge it is simply coded as "spDamageTgtCP:2" but the Groovy code is much longer. The difference, is that by packing so much information into my syntax, produces a much longer code implementation than Shock was to begin with in pure Forge java code.
Not long ago Shock was in cards.txt (as yours) with
Code: Select all
damage:2 target(player|creature)
and I know how it is easy to add similar spells ;)

Java version contained 29 lines of code.
But why I like Groovy more and more is that simple spells are still simple, not one line but:
Code: Select all
   addSpell({
      dealDamage($target, 2, $this)
   })
   setTarget("Creature|Player")
not a lot of code, right? ;)
but I can easily update such spell to target, let's say, only red creatures or gain life on resolve
it will look the same and no need to create new keyword

for sure, both methods have their pros and cons

Also keep in mind that Forge code needs to provide for both the rules, game action and AI of any given effect. MagicWars' Groovy code only needs to describe the action, much of the rules are handled internally, and there's no AI (yet?)
Players often ask me if it's possible to play versus AI. I believe it is sad for them to get to know that the answer is No, no ai in MagicWars. What I can say that I don't want to write script for every card (at least it will take to much time and at the end I will get the clone of Forge with less cards implemented. not my dream ;) So at the moment all I can imagine about AI is not scriptint ai code into every card, but play a card as usual player does and then study the consequences. Actually I've already tried this approach, the next version will include base AI that can play creatures and any removal spells to kill yours - it just plays it in sub game and then tries to find out if anything was changed. I hadn't time to pay enough time for it, it doesn't predict anything (so no way to play two Shocks to kill 4\4). The latest step was thinking over implemenenting Undo function. But I have no idea how to do such in current architecture ;( I read once that Command pattern should be used for such functions but have no info where and how it should be done.
May be one day...
anyway I'm in good spirits as I've just scripted Pyromancer Ascension and very happy about it ;)
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Groovy - script language that runs on JVM

Postby Incantus » 16 Dec 2009, 13:47

Hey nantuko84,
Can you post your code for Pyromancer Ascension? I would like to see your format for copying spells. Thanks!
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Re: Groovy - script language that runs on JVM

Postby nantuko84 » 17 Dec 2009, 07:38

sure, Incantus

here we are:

Code: Select all
def playingTheSameSpellObserver = {o, arg ->
      
      if (arg instanceof Card && (arg.instant || arg.sorcery) && !arg.hasAspect(ASPECT_ALREADY_COPIED_BY)) {
         if (gameManager.graveyard.link.any{it.value.name.equals(arg.name)}) {
             // copy spell
            if ($this.getCounters(CounterType.QUEST) >= 2) {
               copy = CardManager.copyCard(arg)
               // copies can't be copied
               copy.addAspect(ASPECT_ALREADY_COPIED_BY)
               stack.add(new SpellCopy($this,"0",copy))
            }
            
            // put a quest counter
            triggered = TriggeredAbility($this, {
               addCounter($this,CounterType.QUEST)
            })
            triggered.setStackDescription(text[0])
            stack.add(triggered)   
         }
      }
   } as Observer
   
   @entersTheBattlefield({   
      gameManager.eventManager.playingSpellEvent.addObserver(playingTheSameSpellObserver)
   })
   
   @leavesTheBattlefield({
      gameManager.eventManager.playingSpellEvent.removeObserver(playingTheSameSpellObserver)
   })
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Groovy - script language that runs on JVM

Postby Marek14 » 17 Dec 2009, 07:58

"Copies can't be copied" is not completely correct, though... While most copies isn't cast, and doesn't trigger Pyromancer Ascension, copies made through, say, Isochron Scepter would trigger it.
Marek14
Tester
 
Posts: 2773
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 303 times

Re: Groovy - script language that runs on JVM

Postby Arch » 17 Dec 2009, 08:44

Code: Select all
         if (gameManager.graveyard.link.any{it.value.name.equals(arg.name)}) {
             // copy spell
            if ($this.getCounters(CounterType.QUEST) >= 2) {
               copy = CardManager.copyCard(arg)
It looks like the spell is not correctly implemented. It seems to check if there is a card with the same name in the graveyard for both abilites. The second ability should only cares about the number of counters though.
User avatar
Arch
Programmer
 
Posts: 206
Joined: 04 Jul 2009, 09:35
Has thanked: 0 time
Been thanked: 15 times

Re: Groovy - script language that runs on JVM

Postby nantuko84 » 17 Dec 2009, 09:55

Marek14, Arch> thanks for pointing it out!

updated observer:
Code: Select all
   def playingTheSameSpellObserver = {o, arg ->
      
      if (arg instanceof Card && (arg.instant || arg.sorcery) && !arg.hasAspect(ASPECT_ALREADY_COPIED_BY)) {
      
          // copy spell
         if ($this.getCounters(CounterType.QUEST) >= 2) {
            copy = CardManager.copyCard(arg)
            // shouldn't trigger Pyromancer Ascension again
            copy.addAspect(ASPECT_ALREADY_COPIED_BY)
            stack.add(new SpellCopy($this,"0",copy))
         }
         
         // put a quest counter            
         if (gameManager.graveyard.link.any{it.value.name.equals(arg.name)}) {
            triggered = TriggeredAbility($this, {
               addCounter($this,CounterType.QUEST)
            })
            triggered.setStackDescription(text[0])
            stack.add(triggered)   
         }
      }
   } as Observer
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Groovy - script language that runs on JVM

Postby nantuko84 » 18 Dec 2009, 06:18

Yesterday, I realized that it won't work for Charms (with Choose one), as copy was implemented as playing then once again but without any cost (so user was asked to choose one once again).
it was fixed, but now I'm thinking over copying Command cycle spells from Lorwyn (with Choose two: Primal Command, Cryptic Command, etc.). I do believe the rules are the same: when you copy the spell, it will have already chosen effects and you can choose only new targets for them. that means if Cryptic Command in the stack returns permanent and draws a cards, then copy will also return and draw (may be returning another permanent).
if so, then unfortunately it's not impossible to implement copying correctly in MW as such spells have several abilities and they are put into the stack separately

1. does Forge have Lorwyn Commands and how were they implemented?
2. are there any other special cases for copying spells in the stack?
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Groovy - script language that runs on JVM

Postby Marek14 » 18 Dec 2009, 08:29

nantuko84 wrote:2. are there any other special cases for copying spells in the stack?
Basically, the copy remembers all choices made for the original. For example:

A copy of kicked Burst Lightning will still be kicked.

A copy of Blaze will have the same value of X as the original.

A copy of Fling will be considered to have sacrificed the same creature and will deal damage according to its power.

A copy of spell with buyback paid will return to hand after resolving (and promptly cease to exist as SBE). I don't think this matters for anything, though.

However, the copy doesn't remember exact mana paid for the original - so copy of spell cast with Boseiju, Who Shelters All, will be counterable, copy of Firespout will deal no damage (since neither red nor green mana was spent on it), and Nix will always be able to counter a copy. Or maybe the copy DOES remember mana and these are because the copy wasn't cast so no mana was spent to CAST it. I'm not 100% sure.

A copy of spell from a split card will be the same spell - never the other one.

A copy of ability (made by Rings of Brighthearth) will have the same source as the original - if the original would put a +1/+1 counter on its source, the copy does the same, for example.

Basically, you have announcement of spell, where you select various variables for the spell. When you copy a spell, ALL the variables are copied verbatim.
Even targets are copied - this is why most copy spells explicitly allow you to change the targets.

Also, as the copies are not cast, they do not trigger anything that triggers on casting (like lucky charms) and they don't count for storm.

Note that the ability epic is quite strange in this respect - not only does it do sort of "imperfect copy" (copies the spell in all respects except for its epic ability), but it also can copy the original spell even many turns after it resolved and was removed from stack. The same thing is true for Ertai's Meddling.

Finally, note that all of this is only valid for cards that copy SPELLS (anything with conspire, epic, gravestorm, replicate or storm plus Chain Lightning, Chain of Acid, Chain of Plasma, Chain of Silence, Chain of Smog, Chain of Vapor, Chain Stasis, Cloven Casting, Ertai's Meddling, Fork, Glimmervoid Basin (Plane), Hive Mind, Ink-Treaded Nephilim, Izzet Guildmage, Izzet Steam Maze (Plane), Mirari, Mirror Sheen, Mischievous Quanar, Odds // Ends, Pyromancer Ascension, Radiate, Reiterate, Rings of Brighthearth (this one copies abilities, not spells, but otherwise works the same), Sigil Tracer, Twincast, Uyo, Silent Prophet and Wild Ricochet).

There is also a class of cards that copy CARDS and let you cast those copies. In those cases, the announcement is done normally, so all normal choices can be made for the spell. This class contains Eye of the Storm, Isochron Scepter, Jhoira of the Ghitu Avatar (Vanguard), Maelstrom Archangel Avatar (Vanguard), Panoptic Mirror, Reversal of Fortune, Spellbinder, Spellweaver Helix and Spellweaver Volute.
Marek14
Tester
 
Posts: 2773
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 303 times

Re: Groovy - script language that runs on JVM

Postby nantuko84 » 18 Dec 2009, 08:56

thanks a lot for such detailed explanation!!! I'm really implessed =D>

just wonder how you keep in mind all these card names ;)
nantuko84
DEVELOPER
 
Posts: 266
Joined: 08 Feb 2009, 21:14
Has thanked: 2 times
Been thanked: 9 times

Re: Groovy - script language that runs on JVM

Postby Marek14 » 18 Dec 2009, 10:09

nantuko84 wrote:thanks a lot for such detailed explanation!!! I'm really implessed =D>

just wonder how you keep in mind all these card names ;)
A huge text file of all cards and search function is my friend :D
Marek14
Tester
 
Posts: 2773
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 303 times

Re: Groovy - script language that runs on JVM

Postby Incantus » 18 Dec 2009, 13:04

Hey Marek,

A question about Chain of Acid. When the copy resolves, do you put a new copy on ad infinitum until you no longer have a valid target?
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Re: Groovy - script language that runs on JVM

Postby Incantus » 18 Dec 2009, 13:06

Also, when you copy a permanent spell with Isochron Scepter, is the resulting copy a token? What is it when it enters the battlefield? Just a regular card?
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 48 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 48 users online :: 0 registered, 0 hidden and 48 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 48 guests

Login Form