AgendaItems have two parameters that seem redundant to me – initiallyActive and isReady. Is there some reason why AgendaItems should be made active during game initialization? If not (and indeed, the default is nil), does it make any difference whether I delay the activity of the AgendaItem by setting initiallyActive = true and isReady = nil or vice-versa?
Or is this distinction only of value for an NPC who needs to do something on the very first turn (hence initiallyActive)?
initiallyActive is purely for convenience - a way to add an AgendaItem to an NPC’s agenda at startup without having to roll your own InitObject / PreInitObject for that purpose. You have to add them somewhere; the NPC’s executeAgenda routine only knows about the AgendaItems in their list. It checks them all, picks the first one where isReady returns true, and then runs it.
You might have a guard NPC with a lot of behaviors - patrolling a route, calling for help if attacked, running away if wounded, heading toward suspicious noises - all of which are always active and ordered by priority, but which are only ready under the right conditions. It would make sense for those AgendaItems to be initiallyActive so your guard starts the game able to react without having to call addToAgenda() in the action handling for any input that might trigger a response.
You could also have an NPC that only does a few, more heavily scripted things - like disarming a bomb - only one of which will be active at a time, and which will always be ready when active. Here you can set initiallyActive to nil, isReady to true, and call addToAgenda() in the code that starts the scene.
Or you could have a hybrid approach - a guard that does the normal stuff and then tries to disarm the bomb once the player tells him about it.
Thanks – addToAgenda() is the piece of the puzzle that I didn’t know about.
But unless I’m misunderstanding something, there doesn’t seem to be a reason not to always make initiallyActive true for every AgendaItem. There seems to be no penalty for doing this.
It seems to be purely a matter of taste whether to use the defaults for the class (initiallyActive = nil, isReady = true) and call addToAgenda; or whether to make initiallyActive true for an AgendaItem and then either (a) write a method for isReady that will return true when certain conditions are met, or (b) just leave isReady = nil and add a line like
juliaTrekToRidge.isReady = true;
…when it’s time for that AgendaItem to start running.
Right, you can definitely do that. I like your a & b approaches.
If you had a lot of AgendaItems with very complex isReady conditions - ones that iterated through the object tree, or tested whether some very big number modulo the turn count was relatively prime - you might see a performance hit, especially if most of the conditions returned nil. The penalty in this case is that you do a lot of calculation every turn and the NPC winds up not doing anything at all.
On modern hardware this is not something I would lose sleep over, but I suspect it’s half the reason behind the current defaults. The other half could be that addToAgenda(x) is better from an object-oriented perspective than x.isReady = true, since you aren’t breaking the object metaphor by reaching inside a nominally black box and setting a property directly.
From my point of view, setting isReady seems better than using addToAgenda, because it encapsulates all the AgendaItem’s logic within the item. I can just look at a particular AgendaItem and say, “Right, that’s activated when the NPC learns this piece of information,” which saves time writing comments and/or being confused about what I was trying to achieve.
For what it’s worth, all the AgendaItems in my WIP are initiallyActive, and use isReady to check whether they’re available or not. I haven’t had any problems with that approach, but I don’t have that many AgendaItems and the way they interact is tightly controlled. If I had more AgendaItems, or if I was going for a less scripted, more AI-ish approach to NPC actions, addToAgenda might be a more attractive choice.