Here is an example having two npcs moving randomly through the rooms of an apartment. First we go to StoryInit and assign each room their proper exits and give the npcs their starting location:
<<set $bedroom to {
name: "bedroom",
exits: ["hallway"],
}>>
<<set $hallway to {
name: "hallway",
exits: ["bedroom", "bathroom", "livingroom"],
}>>
<<set $bathroom to {
name: "bathroom",
exits: ["hallway", "livingroom"],
}>>
<<set $livingroom to {
name: "livingroom",
exits: ["bathroom", "hallway"],
}>>
<<set $rooms to [$bedroom, $hallway, $bathroom, $livingroom]>>
<<set $john to {
name: "John",
room: "bedroom",
location: $bedroom,
}>>
<<set $marie to {
name: "Marie",
room: "bedroom",
location: $bedroom,
}>>
<<set $npc to [$john, $marie]>>
Next we set up a widget in a properly tagged passage that handles the movement of the npcs by randomly choosing one of the exits of their current room before updating their new location. Additionally we let the player know where the npc went should they be in the same room:
<<widget "move">><<nobr>>
<<set $args[0].room to $args[0].location.exits.random()>>
<<if $args[0].location.name == passage()>>
$args[0].name heads to the $args[0].room.<br>
<</if>>
<<for _i to 0; _i lt $rooms.length; _i++>>
<<if $rooms[_i].name == $args[0].room>>
<<set $args[0].location to $rooms[_i]>>
<<break>>
<</if>>
<</for>>
<</nobr>><</widget>>
And that's basically it. Whenever we call this function, the specified npc moves to a random passage connected to their current one.
To test out the code we trigger it for both npc in the PassageHeader passage - meaning that whenever a player enters a room, both npcs move - also we add a wait button that just reloads the passage:
<<nobr>>
<<for _j to 0; _j lt $npc.length; _j++>>
<<move $npc[_j]>>
<</for>>
[[Wait|passage() ]]<br><</nobr>>
In the PassageFooter we put some code letting the player know when there is an npc present in the room:
<<nobr>>
<<for _i to 0; _i lt $npc.length; _i++>>
<<if $npc[_i].room == passage()>>
$npc[_i].name is here.<br>
<</if>>
$npc[_i].name: $npc[_i].room<br>
<</for>>
<</nobr>>
This method will of course be too work intesive if you have a lot of rooms, like in a procedurally created dungeon labyrinth - in that case you could create a system with coordinates adding and substracting from the x and y coordinates of the npc to move them across the map as long as the new tile in question is one that can be moved upon.
But I think this should at least show the rough principle of one possible way to implement npc movement.