Again, I'm far from an expert on the AI, and even after looking at the AI action code I still don't understand exactly how repeated attack actions would mesh together, but I don't see anywhere where another order is issued to the AI between actions, so as long as the AI has an attack/assassinate goal, it should seamlessly process consecutive attack actions.
Therefore, I can only conclude that having the action's timer come due in the middle of an attack animation or just before an actual fire event begins is the only thing that would cause interrupted or slower attacks now. This could be completely off base, and maybe it's switching actions to and from the attack actions and I'm just not aware of it, but if it's sticking with the attack actions, and things are going slowly/being interrupted, I'd guess that this is a function of asymmetric action timer / ROF timer.
There are a few ways to fix this. I'm not sure that a one-shot action timer is a good solution, because this would radically increase the amount of processing overhead once the AI reached a high rate of fire.
However, it should still be possible to have a semi-enforced timer length, while making the exact action timer a multiple of the demigod's ROF. The simplest way would be:
- local duration = 0.1 + unit.Sync.AttackTime * math.floor(ActionDuration / unit.Sync.AttackTime)
With a default ActionDuration of 3s, this would produce values at ROF delays like so:
Make sense? It wouldn't require any significant changes to the architecture of the action functions, or any serious re-evaluation of weight calculation, but it would keep the timer from straddling an attack event in most cases.
Another, possibly simpler and more effective way to do this that just occurred to me is to have every attack action set a var on the unit or its brain that holds a handle to or entity id of the last target that it was assigned, and clear this out using a ~.3s wait thread at the end of the action. If an attack action finds this value (which would only happen when going straight from attack action to attack action) and it is equal to the assigned target, it kills the thread and skips the IssueClearCommands/IssueAttack part of the action function, so attacks simply proceed seamlessly until a non-attack action or an action against a different target is issued.
Edit: Oh, crud. The ActionWrapper thread in HeroAIActions.lua DOES do an IssueClearCommands. Great. So the timer-manipulation fix is the only viable one, because there's no way to stop it from clearing orders and halting an in-progress attack without overriding ActionWrapper and adding some kind of action-specific exception where commands are not cleared if it's an attack action (whereby each attack action would need to be altered to do their own conditional clear commands based on whether or not they have a target carried over from a previous action).