I'm looking for advice on designing the architecture of my turn-based game.
Suppose units have different abilities—various movement types (run, teleport, charge in one direction, etc.), different melee, ranged, and thrown attacks, as well as other actions like interacting with objects or managing inventory.
Each ability has its own rules, which I generally describe in a CanExecute function. This function checks whether the unit has enough time units, the necessary inventory items, is in the correct state, and so on. If everything is okay, then the ability can be executed via the Execute function.
For example, the CanExecute for a "move" ability checks if the unit has enough time units to reach the destination, and Execute then actually spends those time units.
This system works great when I'm controlling units manually. However, I ran into a problem while implementing the Utility AI.
Let’s say I have an AI action called "move and melee attack." To evaluate it, I enumerate all reachable cells using the "move" ability, and for each of those, I want to evaluate the possible targets for the "melee" ability.
The problem is that my current implementation of CanExecute uses the actual state—position, time units, ammo, etc. That means a chain of CanExecute calls without actual execution leads to incorrect results, because the result of action B depends on action A having been executed.
Splitting this into two separate actions (move, then attack) doesn't help much either, since I still need to know whether moving to a cell is meaningful. I could move into position and only then discover I don’t have enough time units left to attack.
I'm considering simulating action outcomes so I can chain CanExecute calls. At the very least, I’d need to simulate parameters like ammo, time units, position, and facing. But I want to avoid duplicating logic, and I’m struggling to find the right approach.
I suspect I need to move toward more stateless functions and immutable objects. What do you think? Could I be going in the wrong direction? Should the validation logic in the ability system and the AI be separated, and would that even count as duplication?