Step 1
So, there is a Monitor Manager for "Companion Self Healing" which looks at Nurse Grimes + Robo-Brain and says, you should be allowed to self heal. They are in a FormList of allowed to self-heal followers that's part of the heal self monitor manager (i.e. HealSelfAllowedFormList), so the monitor manager gives them a "Self Healing Monitor Token."
Step 2
We fight some baby deathclaws and nurse Grimes and Robo-Brain are injured as the fighting continues. The self healing monitor says, 'oh my, you only have 25% life left' and adds Nurse Grimes and Robo-Brain to HealSelfQueue.
Right
Step 3
Now, the HealSelfDispatcher is running/being processed (as a quest/script?) in the background as it is in the ActiveDispatcherFormList. The GlobalScheduler (another quest/script?) ticks over says, "HealSelfDispatcher, run your check through the HealSelfQueue and see who needs healing up".
The dispatcher is a quest with a stage function at index 1. Thats where everything it does is implemented, it doesnt have a normal questscript running in the backgorund (other than maybe to declare some variables used for state). The GlobalScheduler is a quest with a script that gets executed every t seconds in gameMode, and it iterates through all dispatchers in ActiveDispatcherFormList (= a form list containing the dispatcher quests) and calls setStage quest 1 on each of them.
Step 4
The HealSelfDispatcher sees both Nurse Grimes and Robo-Brain in the cue to self heal. It decides that Nurse Grimes needs to use the HealSelfFleshNBloodEventHandler (for living things of course) and that Robo-Brain needs to use the HealSelfGearsNGreaseEventHandler. These are each called/activated on their respective actors.
The HealSelfDispatcher doesnt contain any decision logic since that would mean whenever you wanna add some new handler you'd also have to change the dispatcher. Instead, the dispatcher simply iterates through all handlers for this event.
The dispatcher somehow has to pass the currently referenced companion to the handler, preferable with a helper variable in some global quest (no concurrency issues since everything is executed sequentially). The handler itself will then decide, whether to accept the reference and do something with it, or leave it for another handler and just return (so HealSelfGearsNGreaseEventHandler will check for robots, and HealSelfFleshNBloodEventHandler for humans). Once a handler accepted a reference, it can tell the dispatcher (again, via helper variable), so it wont pass it on to more any other handlers.
Step 5
The HealSelfFleshNBloodEventHandler goes off, and Nurse Grimes uses a stimpak to heal herself. The HealSelfGearsNGreaseEventHandler runs and Robo-Brain unplugs his old runny brain and installs a fresh one, healing him up. These event handlers remove Nurse Gimes and Robo-Brain from the HealSelfQueue.
Right, except that the dispatcher is in charge of removing the elements, since the handler itself probably doesnt even have to know from which dispatcher it was called, though im not sure if thats really necessary, i tried to think of a scenario where it would make sense for one handler to be called by different events, and i couldnt come up with any, mainly because the examples i picked for events are already pretty specific. For example, the HealthMonitor says "low on health -> heal yourself". "Low on health" could also be an event itself, so the monitor just adds a companion to the LowHealthQueue, and in the handler list for the LowHealthDispatcher are HealSelfGearsNGreaseEventHandler and HealSelfFleshNBloodEventHandler, which would be the same handlers that are also in the handler list of HealSelfDispatcher for the normal "heal yourself" dispatcher. The LowHealthDispatcher then could also contain an additional handler, which causes the companion to flee instead if you treated him badly before
Step 6
Now were back the default state. Nurse Grimes + Robo-Brain are healed. The scheduler keeps initiating the Dispatchers at period intervals, which see that it's que is empty, and resets (until such time that the followers get injured again).
Is that basically how it all works?
Yes, overall thats how i imagined it.
3) FeatureXDispatcher quest/script to be inialized by the global scheduler. In fact, you could merge the functionality of the dispatcher with the monitor manager right?
The Dispatcher is more like a "function object", while the monitor manager has a different task. It would not be a good idea to merge them together, especially since theres not necessarily a 1:1 relation. Not all events require monitors (direct commands issued by the player for example).
4) FeatureXEventHandler quest/script to execute the desired action. The scripting for the event handlers could be integrated right into the monitor token too right?
Same issues as before. If you mean adding the action thats taken to the monitor, thus making all the dispatcher and stuff unnecessary, you COULD do that to create a much simpler system, yes. The problem, besides that this wouldn't be as easy to extend, is that each monitor acts more or less in isolation. It will notice a condition and execute the necessary steps itself, not knowing if there's any other monitor token active which tries to do the same.
You dont necessary have to create all of the mentioned entities if you wanna add something new.
For example:
You can create a new MonitorManager + a set of MonitorTokens to implement some new intelligence, but reuse existing events and handlers (= just use existing queues, no changes required)
You can create a new Event (=Dispatcher, EventQueue, HandlerList for the dispatcher) and a monitor that makes use of it. This event uses some existing handlers, but also defines some of its one which are exclusive to this event.
You can create your own handler and add it to an existing event dispatcher.
Edit:
Aaand.. since i mentioned this earlier with the flee on low health example, it would probably be a good idea if calling the event handlers by the dispatcher would happen in two phases to establish a priority:
So phase 1:
short priorityshort winnerFor every handler i=0...nset Helper.currentRef to queuedRef ; (companion reference for helper)setStage handler 0 ; (handler sets priority var, depending on priority or 0 if he rejects the ref)if Helper.priority > priority set priority to Helper.priority set winner to iendif
The handler with the highest priority value is selected, and in phase 2 gets executed with
set hand to listElementAtIndexBlah HandlerList winnersetStage hand 1