DennisBergkamp wrote:Yes, you're probably right, even though this is quite a tricky task. I'm not much of an architect, maybe someone (you, jpb, Orpheu or forge?) could lay out some kind of design/plan of how to do such a revision exactly? And what parts of the current structure should be revised? Probably many, many parts. That way we could discuss and (hopefully) agree on a good design.
I suppose a lot of us were counting on V2 to fix issues like these, but then again V2 might never come out.
Here's what I do when stuck on a particular design - just review the comp rules for that section of the design. Usually they are so detailed, they almost spell out an implementation that will be rules correct. For example, the layering system screams "use a list to store all relevant continuous effects, so they can be easily combined as necessary". I basically use what I call a stacked_variable object, which basically acts as a simple variable. However, behind the scenes, this object actually implements a list of all relevant continuous effects. So for example, say you have a permanent that's red.
card.color == "R" will return True
color is a stacked_variable which overrides the equality symbol, to make it equivalent to set membership. So the base value of the characteristics is stored as a set, and the stacked_variable contains a list of additions/overrides that can either add to or remove from the base set (a set in this case is a container that mimics a mathematical set). So if you have a red and white creature, the following are true:
card.color == "R"
card.color == "W"
Then you play a card that sets it's color to blue:
card.color.set("U")
this basically adds a characteristic setting object to the list (which basically clears the set and adds the overriden characteristic - compare with cards that say - "Target is blue in addition to its colors", which simply adds a new value to the set). So now, card.color == "R" returns False, while card.color == "U", but internally, the color object looks like:
List(Characteristics("R", W"), Characteristics("U"))
So each stacked_characteristic object supports the following functions:
card.color.set() - replaces the current value
card.color.set_copy() -- for the copy layer, it sticks it into the list in the right position (basically after the last inserted copy effect)
card.color.add() - adds another value
card.color.remove() - removes a value (i haven't seen any cards that really use this, but you could imagine - "Target red creature is no longer red", some kind of hybrid busting card)
card.color.add_all() - not really necessary for color, but think of creature types and changeling
also, implementing it as a set means you can do intersection as well (for hybrid, or a lot of the cards from the Lorwyn block):
say card is an Elf Warrior:
card.types.intersects(("Elf", "Wizard")) returns True, while card.types.intersects(("Goblin", "Wizard")) returns False.
I believe Java has a basic Set class, so this architecture could be easily ported. I also do this for the controller (even though it's not a characteristic) to make it easy to change controllers.
I hope this makes sense.