Page 1 of 1

How do you handle static abilities?

PostPosted: 25 Mar 2009, 14:21
by Incantus
As far as I can see, there are 2 ways:

1. At each "moment" of game time (basically whenever the game considers an atomic action to have occurred), you go through all curently active static abilities (in play, in the graveyard (Riftstone Portal)) and perform their modification. This is very straightforward (reset all cards at each point, add any relevant changes from static abilities) and is more correct from a rules standpoint, but seems very inefficient (especially if you build a search based AI). One side benefit is that timestamps are properly maintained, and conditional static abilities are pretty easy ("[cardname] gains +1/+1 while it is red")

2. Static abilities add or remove their modifications to cards at definite times in the game (for example, when coming into play or leaving play, if the static ability modifies other cards, then it is notified whenever a new card matching its criteria enters or leaves play). This requires an event system (but then again, you need one for triggered abilities). This might lead to some tricky timing or ordering issues (depending on how the event system is setup), and is also less straightforward to implement. One side effect is that getting this right makes triggered abilities fairly easy (the logic is pretty much the same, except instead of creating a continuous effect, you put something on the stack that resolves later).

Incantus currently uses the second approach. It took a while to get the timing right, but now it works pretty well.

What do the other programs do? Anybody have other approaches?

Re: How do you handle static abilities?

PostPosted: 25 Mar 2009, 20:32
by MageKing17
The second approach also gives you a psuedo-dependency, because whenever something changes a static ability's controller (for example), it changes the order in which its effects are evaluated (relative to other static effects). This is somewhat good (using Confiscate on a Control Magic enchanting a creature enchanted by two Control Magics gives you control of the creature), but nonetheless incorrect (if whatever caused the "dependency" disappears, the other effect doesn't revert to its original timestamp).

Re: How do you handle static abilities?

PostPosted: 25 Mar 2009, 22:04
by BlackMamba
Didn't implement those yet :) I'll listen carefully to what you say!

In Mox, I plan to have some sort of "stack" of modifiers for each property. A static ability will add a modifier to that stack, which will retrigger the computation of the "final" value (and possibly of other properties that depend on it). That modifier would listen to the game events that can affect its outcome. That "modifier stack" would also handle dependency layers, timestamps, etc...

Re: How do you handle static abilities?

PostPosted: 26 Mar 2009, 02:07
by frwololo
For Wagic I do it in the most dirty way ever: each time I refresh the screen (which is basically what I decided to consider as an atomic event in my initial design).
This is wrong in two ways:
1) the checks are called many times when nothing actually happened
2) There might be two different event triggered at a same time, not taking each other into account (race conditions).

Now, it was very convenient to do it this way when I started working on my project, and so far it works alright, except in very extreme cases that I decided not to care about (but that a professional MTG player would hate me for). As a programmer I should hate myself for introducing these race conditions in the first place, but I haven't had any real issues so far with it.

Also, the 1) issue is not really one given the very "small" environment we work in.Statistically, there is very little chance to have more than, say 10 static abilities in play at a given time. Also, I have efficient data structures involving hashes for that. Even 100 cards would be fine I guess, but if I had 100 cards on the PSP screen, static abilities would not be my main problem, UI design would be :lol: .

That being said, I started implementing events in my engine and will probably progressively switch to that.
A good point with refreshing at every frame is that I don't really have to care about what is an atomic event or not, I am not afraid of forgetting something. But an Event mechanism is probably the way to go (the only real issue being to avoid infinite loops, I guess...that and not forgetting an event)

Re: How do you handle static abilities?

PostPosted: 26 Mar 2009, 20:49
by MageKing17
BlackMamba wrote:In Mox, I plan to have some sort of "stack" of modifiers for each property. A static ability will add a modifier to that stack, which will retrigger the computation of the "final" value (and possibly of other properties that depend on it). That modifier would listen to the game events that can affect its outcome. That "modifier stack" would also handle dependency layers, timestamps, etc...
That's basically how we handle characteristics and overridden functions (we even call them stacked_characteristics and stacked_functions).

Re: How do you handle static abilities?

PostPosted: 15 Apr 2009, 19:53
by mtgrares
My 2 cents isn't worth much, but here it is. MTG Forge actually uses method 1. To begin with I had no idea how to implement even simple static abilities like Glorious Anthem so I just wrote MTG Forge with the hopes that I could solve the problem in the future. MTG Forge uses method 1 because it was the only way I knew how to add Glorious Anthem and the implementation is still a little bit hacky since I use static class variables. Getting static abilities like Glorious Anthem to work together with pump spells like Giant Growth has been a problem but was fixed with a simple layering system of two ints. If you pumped up a creature with Giant Growth, Glorious Anthem would "reset" the creature's attack. The same problem is trying to pump up Nightmare because Nightmare's code would reset its power and toughness.

I say use whichever method that works for you and if you current method isn't working, change it.