Sunday, 10 October 2010

Dependencies Suck

Over on UserVoice, there are several requests for changes and fixes around dependencies. The thing is dependencies have deeper problems, and I didn't want to spend time trying to patch up a broken system. Instead what's needed is a complete overhaul. However only recently have I come up with a way to get them to work. 

Warning: It's a bit of a long post. If you've spent time creating catalogue files and battling with dependencies, you might want to read on to see what's changing. I've set up a forum post to discuss the changes or ask questions.

So What's Wrong With Dependencies?
Restrictions on selecting units can change depending on what has already been selected. It wasn't until soon before the release of BattleScribe that I decided it would need some kind of simple logic system to represent these changes. Dependencies were born - the idea being that being able to select something depends on what you have selected of some other unit. The problem was, they were hastily dreamed up and just sort of added on at the last minute.

Firstly, the dependencies' conditions can't be combined. This limits their flexibility to represent different situations - for example you can't say "apply dependency if you select Y and Z" or "apply dependency X if you select Y or Z". You can never quite seem to get them to do what you want.

Secondly the error checking mechanism for dependencies is separate from that of the normal restrictions on entries (min/max selections, points etc). This leads to conflicting errors where no matter what you do, either the entry or the dependency shows an error. Essentially dependencies impose their own separate set of rules on what you can select in your roster. They aren't integrated into the general error checking.

Finally, because it was rushed together, the dependency code is a mess - buggy and hard to maintain. It needs rewriting to make it easier to fix problems in future.

What's the Solution?
I've decided to change dependencies to something new: Modifiers. The idea is that a modifier makes changes to an entry if certain conditions are met. A modifier will can change any min/max restriction an entry or entry group. They can increment a value, decrement it or set it to a specific value. This change can be applied once, or multiple times depending on how many selections from another entry have been made. The normal error checking of entries then handles displaying a message. 

A modifier can have one or more conditions that have to be met before the changes are made. They can also have one or more condition groups which join together a set of conditions (or more condition groups) with an "and" or an "or".

A condition is based on either the number or the points value of selections from an entry or entry group. This can either be within the parent selection or in the entire roster. A condition has a value to test this selection count or points total against. The tests are "equal to", "greater than", "less than", "at least", "at most". So for example you could have conditions that say things like:
  • if points total of selections of entry in entire roster is greater than 100
  • if number of selections of entry in it's parent selection is at least 1
  • if number of selections of entry in it's parent selection is equal to 0
An example. Death cult assassins in the Daemonhunters catalogue can only be selected if you have already chosen an inquisitor or inquisitor lord. To represent this, they could have a modifier that sets their "max in roster" value to 0. This would cause a "too many" error to appear if you selected any.

This modifier would have an "and" condition group containing two conditions. The first condition would be "number of selections of inquisitor in the roster is equal to 0". The second would be "number of selections of inquisitor lord in the roster is equal to 0". Therefore, you would get an error if you selected the assassins, but you didn't have an inquisitor and you didn't have an inquisitor lord.

This all means some major changes to the file format for BattleScribe. There were other changes to be made here too, so I'm wrapping it all up into one big change. Don't worry though - I'm working on a way to convert old format files to the new format so they'll still work. This will even convert dependencies to modifiers as best it can. I think there will be quite a few issues with dependencies after this change however, so a swathe of bug fixing catalogues might need doing.