My plan for this week was, among other things, to fix ranged combat. It became apparent that the fix required enemies to have their own inventories (so that ranged attacks could be based on ranged weapons that the enemies carried). This led me down the familiar refactoring path, but it was time well spent. Achievements this week:
- Separate inventories for each actor. Each actor can now have its own inventory simply by adding a component. This enables the AI to determine possible actions from the items the actor has. It also allows for future features such as pickpocketing, running out of consumables, and dropping items on death.
- To enable enemies to have their own inventories, I had to decouple inventory from UI. I was most of the way there already, so it wasn’t too much additional work. There’s still room for improvement – equipped items and carried items are separate classes and there’s some redundancy. Separating inventories and decoupling inventory from UI also makes it possible to implement a feature I’ve been thinking about adding – the ability to possess an enemy and view its belongings in the same inventory view used by the player.
- Refactored effects/conditions. Effects (e.g. poison, paralysis, invisibility) were moved from an inheritance structure to a composition structure. This allowed me to merge tile effects and actor effects into a single set of effects that can be applied to anything.
- Swapped out some multi-parameter method signatures with a single predicate parameter. In a few situations, there were multiple methods that applied different criteria to return a subset of values from a list. Using predicates instead of multiple parameters provides a lot more flexibility and is cleaner.
- Item randomization class. There was enough randomization code for items specifically to warrant a randomization class solely for items. This class is primarily used to determine initial item placement. The main method uses a predicate to only certain items such as potions, or items that can be sold in shops.
- Item database class clean up. There’s still some murkiness around prefabs, GameObject instances, plain old objects, and instances vs types for actors, items, and tiles. The item database class, which is responsible for loading and storing item types, received a good scrubbing.
- Durability refactoring. Item durability code existed in a few places and had some unnecessary coupling. I again applied a composition model and created a class specifically to store item condition and process events that degrade an item’s condition. Since the class inherits from MonoBehavior and can be added as a component, it can be used for objects other than items, such as a wooden door that can be chopped down with an axe. Of course, this could be accomplished with the health attribute as well, and I may in the future eliminate durability altogether and just use health to track an item’s wear.
- Dictionary class extension methods. I added some convenience extension methods to the Dictionary class: an IsEmpty method and a couple of methods to display the contents of entries and the entire dictionary in a readable format.
Next week, I’ll continue fixing ranged combat and some other combat-related bugs.