0
\$\begingroup\$

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?

\$\endgroup\$
4
  • \$\begingroup\$ This is kinda crazy. I dont use this board much and came to ask what turns out to be basically the exact same question. Here was my draft so far pastebin.com/Hu98XEgd. One of the ideas I had was to a have a "draft" state (just local copy of state that doesnt get persisted) that uses the same logic to update it. So in that case it's not exactly duplicated because its calculated by the same functions. Another question for your case specifically, what would happen if you just put the can exectute step in the execute? Would that simplify anything? what are you really gaining by seperating? \$\endgroup\$ Commented May 3 at 2:07
  • \$\begingroup\$ Currently, I'm trying to do in the "draft" state direction too, however, it means that I need to use this kind of state everywhere, in the sequence simulation and in the actual validation/execution. I don't know if it is the right approach. \$\endgroup\$ Commented May 3 at 10:18
  • \$\begingroup\$ As for your second question, the reason that I have CanExecute and Execute separate is that in some places I need to validate before making a move, for example, I need a UI to show the ability button enabled or disabled, depending on is there are any valid targets that I can reach or not. AI also does not want to "execute to validate" as I validate many potential targets, but I can't guarantee transaction consistency and somehow rollback the state of the world each time. \$\endgroup\$ Commented May 3 at 10:23
  • 1
    \$\begingroup\$ What this boils down to is a difference in how your human player vs AI players plan their turns, yes? I'm not following what the difference is between how these two operate. If the AI player operates differently, what are the reasons for that? Does it need to predict further ahead? Not to harp on the obvious, but the system needs to be redesigned from the ground up, to accommodate both. \$\endgroup\$ Commented May 3 at 17:48

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.