Hi and welcome K.L.
I saw your post the other day and started to think about a possible response, but then I thought too much and forgot to reply. I’d now rather ramble about some of my relevant experience in this area than let you keep going without a reply
I wrote Six (ifdb.tads.org/viewgame?id=kbd990q5fp7pythi) a hide and seek and chasing game which has about eight mobile child PCs and a lady walking her dog (and the dog can also move around independently). There are also a few more animals and adults, and one more girl, who stay or appear in single locations but still react to a wide range of things going on in their location.
When I was in the planning stages, I remember looking at Planners and Patrollers and the like, but this was my first Inform game and I was thinking “I will try to keep this simple” (In retrospect: HA!..) as well as just not being sure how I was going to do things. So I didn’t use them and I wrote all the NPC code from the ground up. I just kept adding features as I found I needed them, rather than trying to perceive all the needs of the game in advance. The next time I do a game I might be able to roll some of Six’s behaviours together into more compact code, but I have to say that the code I did write didn’t end up giving me a headache or anything, in spite of its lack of systemisation.
Something I realised as I went along adding relevant behaviours to characters one at a time is that it’s easy to manage this in IF, as opposed to in a real time action game, because actions never occur truly simultaneously in a text game. The game is divided into turns, and when running the code, each line of code executes either before or after another one. As you add in each possible new behaviour, you will know whether to order it before or after the check for some other behaviour within the block of code for one character. And you’ll also be able to answer the question of whether the behaviour checks for this character should keep running or should stop at any particular point during one turn.
The resulting code is easy to follow, in running order and mostly all in one place. Generally I grouped code by the initiating character. So for instance, the main Chapter titled ‘Ayla’ has all the rules and dialogue that Ayla initiates, and it will also (broadly) contain the code and dialogue for other characters that are direct results of those actions.
Back on the topic of the ordering of code, as the author of an IF you obviously also have the luxury of controlling the text output, which is all the player sees concerning what is actually going on. By the same token, this is why I am not a great fan of Inform’s ‘report’ rules scheme. They may be delivered in an order that you can anticipate based on the rules hierarchy, but often you don’t want a list of default messages appearing on separate lines, or even non-default ones. To me, the art of getting the text to flow smoothly is all in the writing together of actions and dialogue that may occur concurrently, especially when you’ve got different characters interacting with each other. If three important actions happen in one turn, to write them together you may need to suppress two of the report rules and write your great paragraph in the third report rule. I am totally non-best-practice in this area and generally only use report rules for movement, but this is not something I recommend per se and it has its own consequences.
One issue I think you should have in mind as you plan and program your game is the extent to which you will or won’t need your NPCs to be subject to Informs built-in rules concerning the physical world and such at different times.
Here’s what I mean by this is - you’ll note that an extension like Planners operates by having the characters ‘really’ perform all actions. If a character needs to drop something, it will be executed in the code by a line like ‘try John dropping the apple.’ Such a line causes John to be subject to all the basic world model rules concerning whether he is capable of dropping the Apple in this location at this particular point in time, and as a result, he may or may not drop the Apple, and his actions will be reported by standard reporting rules if you’re in the same room as him at the time. These are generally all good things, and is the way Inform is designed to work from best practice viewpoint.
But sometimes the default world model can get in the way, or its methods or checks may turn out to be more complex than you need, or create complications that you don’t want.
As an example from my game, there’s one room with a roundabout in it. You can get on or off the roundabout and spin the roundabout from either position. Traditionally you would create such an object in Inform by making it a ‘supporter’. This in turn plugs into a series of rules about being able to climb on and off the object, about the visibility of other characters and their accessibility to you when you’re on the roundabout. But trying it this way, I found that the supporter model had more checks attached to it concerning the enclosing room than I wanted. Going around Inform’s code in the Standard Rules, trying to find all of the relevant bits and writing little exceptions for them to allow the actions I wanted to occur to take place was more painful than just abandoning the world model at this point. So I added a flag to the game which would be 0 if the heroine was off the roundabout and 1 if she was on it. Otherwise, as far as the world model was concerned, she was still in the room containing the roundabout, and not on top of anything. This let all of the usual actions go on in the room and I only had to add new lines to cover exceptions when they came up.
So since NPCs can be subject to all the world model routines that apply to the player - and there are a zillion of them - when it comes to having the NPCs do things, just keep in mind that going outside the routines can sometimes seem to be easier, more efficient or a headache reliever – and sometimes it is! – but also that there are consequences each time you do it. I’d advise special caution where room-to-room movement is concerned, doubly so if you have characters following each other by routines or by your own code. I can say from experience that whenever I ‘teleported’ a character rather than moved them by saying something like ‘try Ayla going south’, it often threw off other movement routines in the game, changed the expected order of movement reporting messages (or eliminated them) or did other tricky stuff that I had to compensate for by writing special subroutines. Sometimes this was essential anyway; given that my game is about characters chasing each other, you’d expect some fiddling in this area. But I probably dug a few more holes for myself than was necessary, and I didn’t know it had happened until after I’d been hacking up movement routines for awhile.
Whew. So in overview, I’d say-
(A) Whenever you have the NPCs do things, be conscious of whether you are executing their actions by the safe-Inform-world-model way, or by going off-road with your own code. There are times when going off-road is the solution, but other times when it is not the solution because although it may be faster in one instance, it may cause unforeseen headaches later. The trick with Inform is that there is acres of code in it already when you begin that you haven’t even thought about.
(B) Whenever you’re about to add some kind of behaviour to the game, check the Standard Rules first to see if and how it’s programmed already, and try it out in the WIP of your game to see how it responds to stuff you type.
© If you know your game’s got some special feature (mine was the chasing/hide and seek commands and features), you will probably want to systematise that behaviour and make sure it’s basically working before you proceed (‘Rapid Prototyping’ they call it). To you, this might involve integrating Patrollers as well. Otherwise, for general character interaction, I’ve demonstrated to myself that it’s fine to just keep adding one interaction at a time, so long as your code is well organised by Character or Location, etc. If you feel stressed about multiple interactions overlapping, just remember that deep down, only one thing can ever happen at a time, and reordering execution order is as easy as reordering your code.