The search for a good core mechanic continues.
I got basic enemy pathfinding working. Rather than having each enemy path independently, they're all being moved as part of a single Dijkstra shortest-paths search, so monsters closest to the player (in the distance metric) move first. This ensures that nobody unduly holds up anyone else.
Working the distance metric out was an interesting problem. If you measure distance strictly based on grid distance from the player then monsters can get hung up because their desired destination is occupied by another monster. In this case they should go around if they can get closer somewhere else. So I made a distance metric that is two components, lexicographically ordered. The dominant component is how many occupied cells are between us and the goal, and the lesser component is how many unoccupied cells there are.
Ultimately I separated the impassable obstacles out into a third score component that dominates the other two. This ensures that monsters won't cluster right on the other side of a wall, because that wall is never going to move. You can see that in effect in the animation above.
The shooting mechanic is problematic. I've experimented with having enemies avoid the hero's line of fire until they get close enough to rush (more path score adjustments), but then you don't get a chance to shoot them at a distance.
I've created a simple signal-strength hunt mechanic. I'm also considering signal directionality. We'll see; I'll keep trying stuff for a day or two.