Birdoggydog's Builds

Giving dungeon monster packs guard, patrol and lair roles

Packs now hold doors, walk routes between rooms or sleep until the party walks in, and two rival factions fight each other on sight while the party watches.

Monster packs in my dungeons have jobs now. A guard holds a door and only chases so far, a patrol walks between rooms, and a lair sleeps until the party walks in. Packs can also belong to one of two factions, and monsters of rival factions fight each other on sight, so the party can stand back and let them. The generator gives every pack a role, and puts a second faction on about a third of dungeons.

49 seconds. A guard turns to a noise, chases and walks home, a patrol comes around a corner and hunts, a lair wakes as the party walks in, and the Meat and the Line fight while the party watches.

Why did the packs need jobs?

Monsters in dungeons were the first thing on my plan for what to build next, because a dungeon was now well built and furnished but its monsters just stood around in packs. Following the party between floors was the other half, and it landed just before this. Roles and factions were two of the gaps the dungeon research had listed back when I started generating dungeon floors. For factions I’d already said “allow 2”, meaning at most two hostile groups in one dungeon.

How is a role laid on a monster?

I didn’t write a new AI for each role. A role sits on top of the existing chase AI. The chase AI keeps its own rules for noticing, chasing and fighting, and the role only says where the monster stands while it’s idle and how far it’ll go. That way a role can’t change how any monster fights, and a pack with no role behaves exactly as it did before. Flyers and the simpler AIs just ignore a role.

Each physics step, a monster asks a raised ally first, then a feud, then its role, then its own mind, and then the role once more so it can look around. Every timer in a role counts game time from the game clock, never real time.

A guard’s post is where it was placed, facing the way it was placed. When it’s idle it turns to face a noise. That’s the party inside its noticing range but out of sight, or another monster chasing or fighting within 15 m. It’ll chase the party at most 12 m, four squares, from its post. Past that it gives up and walks straight home, and only a hit will turn it around on the way.

A first-person view down a narrow rusty metal corridor. A hulking pink, hairless creature walks toward the camera on its knuckles. The party's four portraits and health bars run along the bottom.

The guard Meat Beast coming down the passage after the party stepped under its door, 15 m off.

A patrol walks a route out to the end and back at 0.45 of its speed. The pack walks in single file, because each member sets out 1.5 game seconds after the one before and stops 2 m shorter at the far end. At each end they rest 6 game seconds, wait for each other, and turn around together. A patrol notices the party just like an idle monster does and drops its route to hunt. After the hunt it walks back to the nearest point of its route and carries on from there.

A lair is asleep. It doesn’t notice anything or move until the party sets foot in its room, a fight happens within 15 m, or something hits it. In the film it sleeps in plain sight 18 m away and wakes the moment the party steps in. After 120 game seconds standing idle at home it goes back to sleep.

None of this is saved, on purpose. A lair loaded idle is asleep, which it would be anyway after settling, a patrol walks on from the nearest point of its route, and a guard has no running state to lose.

How does a patrol find its route?

Monsters don’t find paths in this game, they walk straight lines. So the route is worked out when the dungeon is imported. A pack on a dungeon sheet can carry role, faction and, for a patrol, route, a list of squares to walk to in turn. With no route, a patrol walks to the middle of the nearest other room.

The walk goes only through squares the pack’s biggest member fits, never through a door’s square because a shut door would stop it, and never over a ledge. Then it’s pulled straight wherever there’s a clear line of sight with a little width to it, so every leg is a straight walk on open floor. A walk longer than 60 squares is cut there. A patrol with nowhere to go just stands and logs a warning. The import also refuses a third faction on a floor.

What happens when two factions meet?

Two factions are hostile unless they’re named as friends, and for now the Meat and the Line hate each other. Every 15 physics steps a hunter looks for a hostile monster within 14 m with nothing solid in between. It goes for it with the attacks it already has, blows or shots, and keeps at it while that foe lives and stays within 22 m.

The party only comes first while the monster is already hunting the party and the party is nearer. So I can lead a chase into the other faction’s room, or stand back and let two packs meet.

A first-person view down a long blue-gray hall with hazard stripes along the floor edges. Four small monster figures are clustered far down the hall with damage numbers over them, and a text log at the lower left reads lines like Rind Stalker hits Meat Boy for 16.

The Meat and the Line fighting down a long hall, 30 m from the party. The log on the left lists their blows on each other.

A hit from a rival goes through its own path. Resistances count, a guard doesn’t soak it, and the party learns nothing about the monster’s resistances from it. The monster that was hit turns on whoever hit it, never on the party. A kill in a feud leaves the body and its loot for the party to take, but pays no XP, because the party didn’t kill it. Neither side gets put to sleep by the frame-rate code from when I made far-off monsters sleep while a feud is going on.

How does the generator pick roles and factions?

Factions come first. A dungeon gets two factions at a rate of 0.35, decided from the dungeon’s seed so every floor agrees. With two, the floor is split by walking distance between two far rooms, the deepest room and the room farthest from it, and each room goes to the nearer one.

Then roles, from their own random stream, so the packs’ squares and members are the same as before roles existed:

  • one lair per floor, the strongest pack, in the described lair, the boss’s room or else the goal room
  • a guard in the goal room, and in any room with a locked door or a choke near its mouth
  • a patrol in a room with two or more ways out at a rate of 0.5, and the second pack of a room that has two, walking to the nearest other room through no door
  • a guard for everything else

A Python test ran 20 seeds and got 120 packs: 63 guards, 37 patrols and 20 lairs, with two factions on 10 of the 20. The game tests passed 28 of 28 for roles and 18 of 18 for routes. A whole-suite run caught that the monster’s new fields weren’t listed in the save schema, so I listed them as not saved, since the sheet gives them back every time the dungeon is built.

What’s left?

The tour dungeons were generated before roles, so their packs still just stand. A rebuild would show guards at locked doors, patrols walking to the next room, a lair asleep by each goal and two factions fighting on some floors. The designer page doesn’t offer the three new pack fields yet. Every number here is a placeholder for now, and I’ll tune them by playing.