I've decided that I need to implement an aggro system. The turn-based scheduler works by giving each unit in turn a chance to move, and the camera follows the active unit, zooming around the map. While other units are moving, the player is idle. This means that if the map is heavily populated with units, it can be a long time before the player gets to move again. Seriously. Consider that the pacing is currently set at 1/2 second (tweakable). Given 10 movement points per round, that means a unit will spend 5 seconds moving. Granted, spellcasts and other actions can consume more movement points, but the animation staging for a spellcast consumes 3 turns worth of time, so if a spellcast is <3 movement points cost, then you're actually spending more real time for a given movement point. Only for actions that take more than 3 movement points to perform do you start to win back real time. Since many spells are small scale and small cost, I estimate an average of, say, 7 seconds per unit. Multiply by 40 units (where I currently have my test spawn set at) and you're look at 280 seconds for all of those enemy units to finish. That's almost 5 minutes of waiting for a single 10-point combat round. Ugh.
So my answer is an AggravationState component. Enemy units default to a sleep state, and sleeping units are not given a turn for the current round. When a round is staged, units are queried to see if they are willing and ready to act. For AI mobs, this query now involves asking the AggravationState component if anything has happened to make it want to act. Currently, this component does a radius sweep of the map to see if any enemy units are within sufficient proximity to trigger wakefulness. Additionally, as units move they broadcast an event on each hex they move, which all units listen for and which will trigger proximity wakefulness on any unit in range. (This second part is to account for movements that might bring the unit in range of an enemy for only a portion of the path; by rights, even that small amount of exposure should trigger proximity.) Currently, no line of sight is performed, although that is on my plate for this evening, time permitting. If a currently awake unit in an "awake" state (as opposed to "alert", "angry" or "enraged") finds nothing in its proximity sweep then it is safely put back to sleep. (Eventually, I'd like to provide an override for this, for units that shouldn't sleep.)
The aggro component is still in its infancy. It doesn't provide any LoS, no audio-based alarms, it currently doesn't implement damage tracking acts that might trigger an angry or enraged state, etc... and it's extremely easy to game, at least until I implement a proper turn initiative system for the units. But even still, it has greatly decreased the waiting time spent on heavily populated levels, and has brought back some of the intimate, tightly-connected feel that GC once had when it was still a single-pov action RPG.
Because screenshots are fun:
That is a first whack at an apprentice cauldron for brewing potions. Potions will mostly be used for stat boosts (permanent or temporary) although some crafting resources will come from a cauldron as well.
I'm in the process of sketching out a full, if small-scale, scenario as a true gameplay test. It should be fun.