Continuous Effects

Hi,

I could start today’s post by telling you that I have 48% of 10th edition cards implemented. But the bulk of my work in the last weeks was concentrated around a very specific mechanic (continuous effects). Those effects have to be one of the most troublesome mechanic to implement (other developers should agree with this). It is a central mechanic in MTG and so I couldn’t wait any longer to dive into it if I wanted to continue implementing interesting cards.

A few months ago, when I did local effects (R: This creature gets +1/+1 until the end of turn), I did put some thoughts into the more difficult “global” effects as well (White creatures get +1/+1). Without really implementing it, I left hooks and missing pieces here and there with the thought that they would suffice for the global effects. I was wrong. Global effects are evil. So, I shook that code a bit, I dug a bit around in other MTG engines to see how they did it and I finally opted for a new solution. After fixing some performance problems (global effects tend to affect a lot of objects – and they must be checked for update very often), I think I’ve got a working mechanic. I had to change my “effects syntax” (the way I declare effects) in order to support this, but I don’t think there’s any simpler way to do this.

Here’s Nightmare, with a tricky local effect (sorry, the narrow theme makes it harder to read):

[Update: Snacko pointed out correctly that Nightmare’s PT setting ability is a characteristic-defining ability and should be active in all zones. I updated the card definition accordingly.]

public class NightmareCardFactory : FlyingCreatureFactory10E
{
    protected override void Initialize(Card card, InitializationContext context)
    {
        base.Initialize(card, context);

        // Nightmare's power and toughness are each equal to the number of Swamps you control.
        Func<Object, PowerAndToughness> pt = o =>
        {
            int value = ((Card)o).Controller.Battlefield.Where(c => c.Is(SubType.Swamp)).Count();
            return new PowerAndToughness { Power = value, Toughness = value };
        };
        AddEffect.On(card).SetPowerAndToughness(pt, Card.SubTypesProperty).Forever();
    }
}

And here’s Glorious Anthem (a global effect):

public class GloriousAnthemCardFactory : MTGCardFactory
{
    // Creatures you control get +1/+1.
    private class BoostAbility : ContinuousAbility
    {
        protected override IEnumerable<IEffectCreator> AddEffects()
        {
            yield return AddEffect.OnCreatures(Manager, Condition.ControlledBySameController(Source)).ModifyPowerAndToughness(+1, +1);
        }
    }

    protected override void Initialize(Card card, InitializationContext context)
    {
        base.Initialize(card, context);
        CreateAbility<BoostAbility>(card);
    }
}

Notice how some effects need to indicate which properties will trigger the effect to “recompute”. This is not so elegant but is necessary if you don’t want every effect to be recomputed at every property change (and there’s a lot in search-based AI).

Have a good week!

Advertisements

About fparadis2

Lead Game programmer
This entry was posted in Mox. Bookmark the permalink.

3 Responses to Continuous Effects

  1. Snacko says:

    Nightmare actually has a characteristics-defining ability and it should work in all zones even outside of the game. Does it ? 🙂

  2. fparadis2 says:

    Really? I didn’t know that, I thought its ability was limited to the battlefield.
    My first version was implemented like that and I had to work hard so that it didn’t 0_0.
    Oh well, easy to fix.

    Thanks for the input!

  3. Nantuko says:

    you are quick to implement continious effects 😉 hope you didn’t forget about layers

    p.s. went to fix Nightmare, my implementation is also wrong =)
    Snacko is right, some cards like Morbid Bloom may not work if pt is counted only on battlefield

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s