Introduce a new abstraction:
Action represents something that can be done, and encompassed the time aspect as well as information about the state and state transitions of the action. So a reload action definition might contain information about total duration, relative timestamp of reload complete etc. A spear throw action definition contains information about total duration and timestamp of spear release.
Exactly how you wrap this up in code is up to you and depends on your framework/style.
Actions could be simple data objects which you just use to define different actions, and then you make use of the timestamps, durations and other information "manually" in the rest of your code. Or you could improve encapsulation by having your
Action module expose events which trigger when the action changes state (OnReloadStarted,OnReloadReady,OnReloadFinished,OnSpearThrown). Or you could have a medium where there are no events, but the
Action still manages its states/transitions so that you can poll it:
If you have multiple reload animations or spear-throw animations with different timings, then you define each alternative as an action, e.g. FastThrowAction and SlowThrowAction. Once again it is up to you exactly how you manage and pick from different alternatives.
The point of all this is that the
Action abstraction becomes a natural part of the gameplay model when you focus on the concepts that affect gameplay (action transitions/events) and remove the concepts that don't (animation).
Action objects can then be used to drive the animation as well. Whenever a FastThrowAction is started, then your renderer/view starts the corresponding FastThrowAnimation.