My AI is utility-driven in a similar pattern to The Sims, where all unique behavior is coded into interactable objects, and the only thing an NPC does is decide which object they wish to use, path to it, and activate it. This is deceptively powerful, as I can extend nearly any desired behavior by creating a novel object and shaping constraints leading to its selection.
The challenge I'm having with this approach is giving the illusion that NPCs are moving around when the player isn't nearby. The game runs a 24/7 clock and seeks to have each NPC go through the motions of maintaining a regular schedule: going to work, going to bed, and randomly doing weird things in their free time to preserve the illusion of unpredictability. This is implemented with a dict(float time, Appointment appointment), which acts as a global behavior queue and is called every time the in-game clock changes to teleport each AI who has an appointment to use an object to that object's position. This works well enough for prototyping other systems, but it isn't very convincing: you never see NPCs moving through the world, and when you're familiar with a few specific characters it becomes very obvious that they're teleporting around when you can't see them.
Is there a better way to simulate movement around a world with a large number of NPCs, or am I better off keeping my current queue-oriented behavior system and writing an entirely different system to fake movement? My optimal endpoint would be a system that can order NPCs to be at any location, at any time, and trust them to move there in a convincing way, but I worry I'm putting too much detail into a simulation that could fake the same behavior more convincingly with a simpler solution.