It is currently 18 Apr 2024, 03:44
   
Text Size

Incantus Programming Questions

by Incantus

Moderator: CCGHQ Admins

Incantus Programming Questions

Postby mtgrares » 04 Nov 2008, 17:53

Where can I download the new version, it sounds cool. It would be great for someone to write about how Incantus defines a card and how the rules engine works, since you guys seem to understand so much :) :) I would die a happy man if MTG Forge had the whole Shards of Alara cardset.
Last edited by mtgrares on 07 Nov 2008, 18:46, edited 1 time in total.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Where can I get the new version with Shards of Alara?

Postby MageKing17 » 05 Nov 2008, 02:27

Well, if you want a new version, I can compile one for you pretty much whenever. The source changes so often we don't really put versions up for download often, because a bug can be found within five minutes of building a fresh executable. ;)

If you want me to talk your ear off about coding cards or how the rules engine works, I'd be happy to. I did Alara almost entirely by myself, so I have a pretty good idea of how to code any given card. If you have any questions, you can just ask, but if you want a comprehensive overview, I wouldn't know where to begin. :P
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Re: Where can I get the new version with Shards of Alara?

Postby mtgrares » 05 Nov 2008, 19:38

Thanks MageKing. You can post or e-mail the newest version of Incantus. I just want to use it and see how Shards of Alara plays.

Let me think of a few random questions.

1. Do you have one object that takes care of all the rules?

2. How did you program exalted?

3. How hard was Angelic Benediction? I find cards with text like "Whenever a creature you control attacks alone, you may tap target creature" to be hard and confusing to code.

4. Angelsong prevents all combat damage, how do you program that?

5. Ethersworn Canonist is a great card, how did you restrict the player from playing nonartifact spells?

6. Etherium Sculptor reduces the cost of artifacts, how do you code that?

Hopefully I haven't asked too many questions. Programming Magic is a fun topic :)
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Where can I get the new version with Shards of Alara?

Postby MageKing17 » 05 Nov 2008, 22:56

mtgrares wrote:Thanks MageKing. You can post or e-mail the newest version of Incantus. I just want to use it and see how Shards of Alara plays.

Let me think of a few random questions.

1. Do you have one object that takes care of all the rules?

2. How did you program exalted?

3. How hard was Angelic Benediction? I find cards with text like "Whenever a creature you control attacks alone, you may tap target creature" to be hard and confusing to code.

4. Angelsong prevents all combat damage, how do you program that?

5. Ethersworn Canonist is a great card, how did you restrict the player from playing nonartifact spells?

6. Etherium Sculptor reduces the cost of artifacts, how do you code that?

Hopefully I haven't asked too many questions. Programming Magic is a fun topic :)
Not too many questions at all. Good questions, actually. ;)

1. Each card contains its own code, but we define lots of objects and functions that can help with this. MemoryVariables let us do things like keep track of what damaged what else, which cards went into the graveyard, which spells have been played each turn, etc. We also define a lot of "effects functions" to handle things like regeneration, altering power and/or toughness, and (in my version, now) scrying. There's a main "GameKeeper" object that handles turn orders, giving priority, and (if I'm remembering properly) state-based effects. No one object handles everything, unless you were to count the entire user interface as "one object". ;)

2. Exalted was fairly easy, truth be told. I created a new source code file called "AlaraAbility.py", imported a few objects (like TriggeredAbility, the necessary events to hook into from GameEvent, etc.), and wrote this code (well, not exactly this code, but something close to it... it's been upgraded since):
Code: Select all
def exalted():
    def condition(source, sender, attackers):
        return sender.current_player == source.controller and len(attackers) == 1
    def effects(controller, source, attackers):
        yield NoTarget()
        until_end_of_turn(attackers[0].augment_power_toughness(1, 1))
        yield
    return TriggeredAbility(Trigger(DeclareAttackersEvent()), condition, effects, zone="play", keyword='exalted')
To use this with a card, all they have to do is add "abilities.add(exalted())" to their card. It's that simple.

3. Exactly as hard as Exalted, considering the card code looks basically like the function above, except using our decorators (which are easier to code cards with than the TriggeredAbility, CardStaticAbility, StaticTrackingAbility, ActivatedAbility, ManaAbility, or CiPAbility objects themselves), and having the effect tap the target instead of giving it a P/T boost for this turn.

4. Well, I originally had the card itself create a replacement for each of the three damagable objects' (Creature, Planeswalker, Player) assignDamage function (all our damage prevention and replacement targets the assignDamage function of the target, not the dealDamage function of the damager, so that all replacements for damage are offered at the same time), but since this was cumbersome and would need to be copy&pasted for every card with a fog-type effect, I added a "prevent_all_combat_damage()" function to Effects.py which did the same thing.

5. First, I created a new MemoryVariable that kept a log of all the spells a player has played this turn. Then I made Ethersworn Canonist override the "playable" function of CastingAbility (the base class that all casting abilities are based off of, like CastPermanentSpell and CastInstantSpell) to check if the player had previously played an artifact spell and, if so, return False. The actual static ability in Ethersworn Canonist's code looks like this:
Code: Select all
@static(txt=text[0])
def ability():
    def effects(card):
        def playable(self, source):
            return isArtifactCard(source) or len(spell_record.get(source.controller, lambda s: not s.types == "Artifact")) == 0
        yield do_override(CastSpell, "playable", playable, combiner=logical_and)
    return no_condition, effects
abilities.add(ability)
spell_record is the MemoryVariable (we could, if we wanted, create a new instance of this MemoryVariable just for this card, but that would be a waste of resources, and not interact properly with, for example, copy effects), and as you can see, it basically says "If this spell is an artifact or this player hasn't played a nonartifact spell this turn, they can play it."

6. By overriding ManaCost's compute function that reduces colorless mana by one, and using the logical_and combiner (as with Ethersworn Canonist) to make sure it's run in addition to the regular compute function, not instead of it. The card's static ability looks like this:
Code: Select all
@static(txt=text[0])
def ability():
    def effects(card):
        def compute(self, source, player):
            if str(source.zone) == "stack" and source.types == "Artifact" and player == card.controller:
                self.final_cost[-1] -= 1
            return True
        yield do_override(ManaCost, "compute", compute, combiner=logical_and)
    return no_condition, effects
abilities.add(ability)
self.final_cost[-1] would be the last item in the "final_cost" list, which would be colorless mana. You could, of course, also do "self.final_cost[5] -= 1", since it's a 0-based list, and there are only five colors, making the sixth element be [5]. If we wanted to do Edgewalker, it would instead do "self.final_cost[0] -= 1" and "self.final_cost[2] -= 1". I assume, at any rate, that the colors are in WUBRG order. I could be wrong, Incantus doesn't always remember to sort things in WUBRG order. I'm pretty sure mana cost lists are, though.

I hope that answered all of your questions, and feel free to ask more. In the meantime, I'll whip up a version and let you see what mistakes I made. ;)
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Re: Where can I get the new version with Shards of Alara?

Postby mtgrares » 07 Nov 2008, 18:41

Thanks for the reply. I've used Python a little I know you can do wierd things like replace another objects methods. I'm using Java which is just a clean version of C++ and I have to use setters and getters for everything.

Have you implemented anything like Sengir Vampire +1/+1 ability. In the future, I was thinking that my program MTG Forge would need to keep a complete game log of everything that has happened to make delayed triggered abilities easier to program.

Your program is great, I just wish I knew enough Python to slap a basic AI on it. MTG Forge's AI is super basic, play the highest costed card and attack most of the time. I make MTG Forge's AI seem a little bit smarter since I actually add 5-30 lines of AI code for each card like to tell the AI when to play Wrath of God. I'm trying to work on MTG Forge 2.0 that uses only a general AI algorithm like alpha-beta pruning so I don't have to write each card's AI.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Where can I get the new version with Shards of Alara?

Postby mtgrares » 07 Nov 2008, 18:45

Your code for exalted is very short, I envy you :) I haven't tried to code exalted but it seems like my code in Java would be waaaay longer. I try to write as short as possible since it makes debugging easier and it just saves time. Usually short code is good code.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Incantus Programming Questions

Postby Incantus » 07 Nov 2008, 19:39

Hey Forge,

The key thing isn't short code, but generalized code. The reason most card code looks so simple is that Incantus abstracts all the details into a bunch of easy functions that make a mini-DSL of magic, and these functions can be composed together to make almost any ability. If you have any experience with functional programming that's the approach I took. And it definitely helps that python is so dynamic - i'm not sure my current architecture is portable to C++ or java (although it might work with D or IO).

Incantus
Incantus
DEVELOPER
 
Posts: 267
Joined: 29 May 2008, 15:53
Has thanked: 0 time
Been thanked: 3 times

Re: Where can I get the new version with Shards of Alara?

Postby MageKing17 » 07 Nov 2008, 21:37

mtgrares wrote:Have you implemented anything like Sengir Vampire +1/+1 ability. In the future, I was thinking that my program MTG Forge would need to keep a complete game log of everything that has happened to make delayed triggered abilities easier to program.
Sengir Vampire is indeed implemented. The key is that a lot of people tend to assume that it's a delayed trigger. It's actually not.

Sengir Vampire says "Whenever a creature dealt damage by Sengir Vampire this turn is put into a graveyard, put a +1/+1 counter on Sengir Vampire." The only time Sengir Vampire's code actually runs is when the creature goes to the graveyard, not when he damages it. He doesn't set up a delayed trigger, he just looks back to see if he ever damaged that creature this turn. So all we needed to do was keep track of who damaged what, and that's fairly easy (I mentioned MemoryVariables earlier, this is one of those. We have a "DamageTrackingVariable" with an instance named "damage_tracker", so cards can say "damage_tracker.dealt(source, to)" to find out if "source" dealt damage to "to"). We actually got Sengir Vampire working before we did delayed triggers (and yes, we have delayed triggers).

mtgrares wrote:Your program is great, I just wish I knew enough Python to slap a basic AI on it. MTG Forge's AI is super basic, play the highest costed card and attack most of the time. I make MTG Forge's AI seem a little bit smarter since I actually add 5-30 lines of AI code for each card like to tell the AI when to play Wrath of God. I'm trying to work on MTG Forge 2.0 that uses only a general AI algorithm like alpha-beta pruning so I don't have to write each card's AI.
An AI would be nice, but I'm pretty sure the only way to do it would be to do just what you do... add code to each card to give the AI hints on when to use it. Anything more advanced probably either couldn't be written in Python or would be unbearably slow.
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Re: Incantus Programming Questions

Postby commissar » 12 Nov 2008, 11:06

Its an incredibly job you are doing, so =D>

I thought about implementing mtg rule engine in c#, but some of the cards seem realy hard to wrap in code.

1. Have you implemented 418.5. Interaction of Continuous Effects?
2. How about 418.6. Text-Changing Effects?
3. What about cards, that let a player control other player's actions like Mindslaver, Drain Power, ...

If u at anytime decide to go open source, i will be happy to help, i know some python myself.

grega g
commissar
 
Posts: 2
Joined: 12 Nov 2008, 10:52
Has thanked: 0 time
Been thanked: 0 time

Re: Incantus Programming Questions

Postby The Scientist » 12 Nov 2008, 12:59

1. Effects are ordered in layers, for example, if you have Turtleshell Changeling, and you use its abiltiy, then give it +3/+0, it will be a 4/4 (and not a 7/1) as the rules say it should be.
However, there's no implemention of dependency and we're not sure on how to approach it yet. There are some ideas, but atm, none are in effect.
2. These effects are very low on the priority list and we all sort of agreed we will ignore them as long as possible, because it's not easy to do them.
3. incantus told me Mindslaver is technically easy, since you just have to override who makes decisions. But I'm sure there are examples that are a lot harder, like Word of Command and such. Those are pretty hard, but also unique. A whole section of the rules is dedicated to one card, like Mindslaver, and eventually we will find a way, we can always make custom functions, but something like Drain Power is not easy, it's true. I can say that none of those cards are implemented, although some other "unique" cards like Mirror Gallery are implemented already.

If you want to help, you should check out the #incantus channel on efnet, an IRC network.
The Scientist
 
Posts: 94
Joined: 05 Jun 2008, 07:39
Has thanked: 0 time
Been thanked: 0 time

Re: Incantus Programming Questions

Postby commissar » 12 Nov 2008, 15:33

yea i went to irc but everyone was away (or bot)

My idea about interaction of continuous effects was that there is a global class in game, kind of mediator, that is called every time P/T value of an creature was accessed. Mediator would than check all effects, run them through rules and spit out a number that is this creature's P/T
commissar
 
Posts: 2
Joined: 12 Nov 2008, 10:52
Has thanked: 0 time
Been thanked: 0 time

Re: Incantus Programming Questions

Postby MageKing17 » 12 Nov 2008, 17:36

commissar wrote:yea i went to irc but everyone was away (or bot)

My idea about interaction of continuous effects was that there is a global class in game, kind of mediator, that is called every time P/T value of an creature was accessed. Mediator would than check all effects, run them through rules and spit out a number that is this creature's P/T
We recalculate P/T every "timestep" (basically every time something happens). Power and toughness are the easiest things to implement, though. Getting the other layers to work properly is far more complicated, and we basically ignore the problem at this point (until we have a good way to implement dependency, we'll just have to settle for our admittedly-incorrect system).
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Re: Incantus Programming Questions

Postby mtgrares » 12 Nov 2008, 17:56

Getting the other layers to work properly is far more complicated, and we basically ignore the problem at this point (until we have a good way to implement dependency, we'll just have to settle for our admittedly-incorrect system).
Layers are complicated. I didn't realize that my program MTG Forge has a problem until I tried to Giant Growth Nightmare. Since I implement state effects in a very simple way, Giant Growth would technically pump up Nightmare but then the state effect would set the power and toughness, thus negating Giant Growth. But every program should not get too complicated to begin with and should "grow" in complexity as needed, such as a complete layering system, which Magic has around 8 which is just insane. In programming you try to simplify the present while not discounting the future.
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: Incantus Programming Questions

Postby MageKing17 » 13 Nov 2008, 01:07

6, actually, but the P/T layer is divided into 5 "sublayers", and the card itself acts sort of like a "layer 0", so it can get pretty confusing.
User avatar
MageKing17
Programmer
 
Posts: 473
Joined: 12 Jun 2008, 20:40
Has thanked: 5 times
Been thanked: 9 times

Re: Incantus Programming Questions

Postby frwololo » 14 Nov 2008, 05:19

The worst thing with this layer system is that it is actually useful in less than 1% of the games :evil:
As the comp rules say, most people shouldn't even have to read them.
But as a programmer, I think I should have read them before starting my project.
The comp. rules just look like a whole IT project specification. Programming a magic engine while following precisely these rules is probably the only good way (but it's less fun than trying to figuring out stuff by yourself...).

Anyways, this isn't the correct forum to post all this, but it seems the Incantus channel is more active in terms of programming discussions than the dedicated forum, so let me introduce the first "programming related" post on my blog. -> http://wololo.net/wagic/2008/11/10/the- ... rs-to-you/ (lots of inspiration from Forge's blog...but it seems that unlike his blog, my posts get replies only when there's a new release :P )
I've learned lots of stuff from MTGForge's blog, the comp rules, and the discussions on this forum involving the Incantus team. I know we all work with different programming languages, and as programmers we all have different ways to design our code, but it is fun to share our experiences. I'm always happy to see I'm not the only one with P/T effects problems or other stupidly complex rules :D

Am I the only one who's afraid when a new block's coming ? "What, now they can do that ? Oh damn !" (like, the hybrid mana cost ? Come on, how am I gonna put that in my manacost class ???) :lol:
frwololo
DEVELOPER
 
Posts: 265
Joined: 21 Jun 2008, 04:33
Has thanked: 0 time
Been thanked: 3 times

Next

Return to Incantus

Who is online

Users browsing this forum: No registered users and 11 guests


Who is online

In total there are 11 users online :: 0 registered, 0 hidden and 11 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 11 guests

Login Form