Birdoggydog's Builds

Removing a one-way door's pull handle from its blank face

The dark marks on a one-way door's blank side were the door kit's handle and its baked shadow. I cut both, and taught the reach walk about one-way doors.

A one-way door in Blobber now looks bare from its blank side, in all four themes. Before, dark bar shapes showed on the leaf, which I had left as a known flaw in the earlier post about one-way and secret doors. I also fixed the game’s check for whether a dungeon can be walked through, which treated a one-way door like any other door.

70 seconds: the one-way door’s blank face close up at about 0:15, now bare, then walked through from the push-bar side.

Why were there dark bars on the blank side?

The marks looked like the push bars, but the test already showed the bars were only on the handle face. I suspected the bars being seen through the leaf, the second leaf turning half round, and backface rendering. None of those held. I drew the leaf unshaded and then with SSAO and shadows off, and the mark stayed with the leaf both times, so it wasn’t lighting.

The cause was the door kit. Its leaf has a pull handle modeled on both faces, and the handle’s shadow is baked into the leaf’s occlusion and base color textures. So the marks were that handle and its shadow, not the push bars. A cyberpunk leaf has a bar 1.0 to 1.5 m up, a steampunk one has a bar 0.85 to 1.45 m up, a fantasy one has a ring at 1.1 m, and the eldritch leaf has none.

How does the leaf lose its handle?

DoorValve.blank_leaf() makes a copy of the leaf’s mesh and material for the blank face, once per leaf, material and face, and keeps it in a cache. It works in the leaf’s space, with the meeting edge at x = 0 and y up, and one zone covers every theme:

const HANDLE_ZONE := Rect2(-0.36, 0.8, 0.225, 0.76)   # x, y, width, height in meters

The zone starts 0.135 m from the meeting edge so the steampunk strap rivets at 0.15 m stay. The mesh’s vertices are grouped into pieces, where triangles join them or they sit on one point. A piece lies on the handle if every vertex is on that face’s side and inside the zone. Its triangles are dropped and its points are moved to z = 0, inside the leaf’s core where nobody sees them.

That left a dark shape, because the bake was still in the textures. For each dropped piece I find the box of UV space under its footprint on every triangle of the face it overlapped, flat or bevelled. Then I repaint that box, in a copy of the occlusion texture’s red channel and in a copy of the base color, to the middle of what the box’s rim shows. Boxes covered by pieces that still stand in front of the triangle are left alone, since nobody sees them. The blank face also gets no lock panel now.

A grid of twelve first-person views of doors, four rows for four themes and three columns, where the first two columns show plain leaves and the third shows a yellow push bar and a keypad.

Narrow doors, one row per theme: the blank face, the blank face close up, and the handle face with its push bars.

A grid of twelve first-person views of wide doors in four themes, with plain leaves in the first two columns and yellow push bars in the third.

The same sheet for wide doors.

Why did the game’s reach walk need to know about one-way doors?

The game’s walk that decides what the party can reach, used for the dungeon warnings and the lock check, started at the entrance and went through every one-way door as if it were plain. The Python checker already had a “side” gate, so only it caught a dungeon you couldn’t get through. Now DungeonFixtures._walk and DungeonLocks.check both use a few helpers in DoorValve. gates() maps each one-way square to its handle’s square, lets_in() refuses to step onto it from anywhere else, and starts() begins the walk at the entrance and at every ladder stop, since a ladder is come to from another floor. A switch that has been thrown still opens its door.

A one-way door whose handle side is never reached gets a warning, and a locked door’s key behind a blank face now says so in the lock error. DungeonKeys also didn’t know the uid of a one-way door, so a key couldn’t name one. It now reads it as a door, the way the plan does.

Did it work?

tests/dungeon_valves passes 45 checks, and the film’s 16 checks pass. The 21 suite tests on doors, locks, keys and dungeon import had 0 failures, and the warnings for the example dungeons were the same 11 lines before and after.