diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs
index f443373a5c..f569b8b054 100644
--- a/world/src/civ/mod.rs
+++ b/world/src/civ/mod.rs
@@ -258,15 +258,23 @@ impl Civs {
 
             ctx.sim.get_mut(locs[0].0).unwrap().cave.0.neighbors |=
                 1 << ((to_prev_idx as u8 + 4) % 8);
+            ctx.sim.get_mut(locs[1].0).unwrap().cave.0.neighbors |=
+                (1 << (to_prev_idx as u8)) | (1 << (to_next_idx as u8));
             ctx.sim.get_mut(locs[2].0).unwrap().cave.0.neighbors |=
                 1 << ((to_next_idx as u8 + 4) % 8);
-            let mut chunk = ctx.sim.get_mut(locs[1].0).unwrap();
-            chunk.cave.0.neighbors |= (1 << (to_prev_idx as u8)) | (1 << (to_next_idx as u8));
-            let depth = locs[1].1 * 250.0 - 20.0;
+        }
+
+        for (i, loc) in path.iter().enumerate() {
+            let mut chunk = ctx.sim.get_mut(loc.0).unwrap();
+            let depth = loc.1 * 250.0 - 20.0;
             chunk.cave.1.alt =
                 chunk.alt - depth + ctx.rng.gen_range(-4.0, 4.0) * (depth > 10.0) as i32 as f32;
             chunk.cave.1.width = ctx.rng.gen_range(6.0, 32.0);
             chunk.cave.0.offset = Vec2::new(ctx.rng.gen_range(-16, 17), ctx.rng.gen_range(-16, 17));
+
+            if chunk.cave.1.alt + chunk.cave.1.width + 5.0 > chunk.alt {
+                chunk.spawn_rate = 0.0;
+            }
         }
     }
 
diff --git a/world/src/site/castle/mod.rs b/world/src/site/castle/mod.rs
index 60b570bb99..afd2404442 100644
--- a/world/src/site/castle/mod.rs
+++ b/world/src/site/castle/mod.rs
@@ -51,6 +51,7 @@ pub struct Castle {
     towers: Vec<Tower>,
     keeps: Vec<Keep>,
     rounded_towers: bool,
+    ridged: bool,
 }
 
 pub struct GenCtx<'a, R: Rng> {
@@ -114,6 +115,7 @@ impl Castle {
                 })
                 .collect(),
             rounded_towers: ctx.rng.gen(),
+            ridged: ctx.rng.gen(),
             keeps: (0..keep_count)
                 .map(|i| {
                     let angle = (i as f32 / keep_count as f32) * f32::consts::PI * 2.0;
@@ -123,7 +125,7 @@ impl Castle {
 
                     let locus = ctx.rng.gen_range(20, 26);
                     let offset = (dir * dist).map(|e| e as i32);
-                    let storeys = ctx.rng.gen_range(1, 5).clamped(2, 3);
+                    let storeys = ctx.rng.gen_range(1, 8).clamped(3, 5);
 
                     Keep {
                         offset,
@@ -244,9 +246,9 @@ impl Castle {
                         let wall_ori = if (tower0.offset.x - tower1.offset.x).abs()
                             < (tower0.offset.y - tower1.offset.y).abs()
                         {
-                            Ori::East
-                        } else {
                             Ori::North
+                        } else {
+                            Ori::East
                         };
 
                         (
@@ -271,13 +273,15 @@ impl Castle {
                     .map(|(dist, _, path, _)| path.head_space(dist))
                     .unwrap_or(0);
 
-                // Apply the dungeon entrance
                 let wall_sample = if let Some(col) = get_column(offs + wall_pos - rpos) {
                     col
                 } else {
                     col_sample
                 };
 
+                // Make sure particularly weird terrain doesn't give us underground walls
+                let wall_alt = wall_alt + (wall_sample.alt as i32 - wall_alt - 10).max(0);
+
                 let keep_archetype = KeepArchetype {
                     flag_color: Rgb::new(200, 80, 40),
                 };
@@ -294,17 +298,18 @@ impl Castle {
                     let mut mask = keep_archetype.draw(
                         Vec3::from(wall_rpos) + Vec3::unit_z() * wpos.z - wall_alt,
                         wall_dist,
-                        Vec2::new(border_pos.reduce_max(), border_pos.reduce_min()),
+                        border_pos,
                         rpos - wall_pos,
                         wall_z,
                         wall_ori,
                         4,
                         0,
                         &Attr {
-                            storeys: 1,
+                            storeys: 2,
                             is_tower: false,
                             ridged: false,
                             rounded: true,
+                            has_doors: false,
                         },
                     );
 
@@ -329,17 +334,22 @@ impl Castle {
                                 )
                             },
                             border_pos.reduce_max() - tower_locus,
-                            Vec2::new(border_pos.reduce_max(), border_pos.reduce_min()),
+                            Vec2::new(border_pos.reduce_min(), border_pos.reduce_max()),
                             (wpos - tower_wpos).xy(),
                             wpos.z - tower.alt,
-                            Ori::East,
+                            if border_pos.x > border_pos.y {
+                                Ori::East
+                            } else {
+                                Ori::North
+                            },
                             tower_locus,
                             0,
                             &Attr {
-                                storeys: 2,
+                                storeys: 3,
                                 is_tower: true,
-                                ridged: false,
+                                ridged: self.ridged,
                                 rounded: self.rounded_towers,
+                                has_doors: false,
                             },
                         ));
                     }
@@ -364,17 +374,22 @@ impl Castle {
                                 )
                             },
                             border_pos.reduce_max() - keep.locus,
-                            Vec2::new(border_pos.reduce_max(), border_pos.reduce_min()),
+                            Vec2::new(border_pos.reduce_min(), border_pos.reduce_max()),
                             (wpos - keep_wpos).xy(),
                             wpos.z - keep.alt,
-                            Ori::East,
+                            if border_pos.x > border_pos.y {
+                                Ori::East
+                            } else {
+                                Ori::North
+                            },
                             keep.locus,
                             0,
                             &Attr {
                                 storeys: keep.storeys,
                                 is_tower: keep.is_tower,
-                                ridged: true,
+                                ridged: self.ridged,
                                 rounded: self.rounded_towers,
+                                has_doors: true,
                             },
                         ));
                     }
diff --git a/world/src/site/settlement/building/archetype/keep.rs b/world/src/site/settlement/building/archetype/keep.rs
index ee197e3848..476ab57f8d 100644
--- a/world/src/site/settlement/building/archetype/keep.rs
+++ b/world/src/site/settlement/building/archetype/keep.rs
@@ -19,6 +19,7 @@ pub struct Attr {
     pub is_tower: bool,
     pub ridged: bool,
     pub rounded: bool,
+    pub has_doors: bool,
 }
 
 impl Archetype for Keep {
@@ -26,16 +27,18 @@ impl Archetype for Keep {
 
     fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
         let len = rng.gen_range(-8, 24).max(0);
+        let storeys = rng.gen_range(1, 3);
         let skel = Skeleton {
             offset: -rng.gen_range(0, len + 7).clamped(0, len),
             ori: if rng.gen() { Ori::East } else { Ori::North },
             root: Branch {
                 len,
                 attr: Attr {
-                    storeys: 1,
+                    storeys,
                     is_tower: false,
                     ridged: false,
                     rounded: true,
+                    has_doors: true,
                 },
                 locus: 10 + rng.gen_range(0, 5),
                 border: 3,
@@ -46,10 +49,11 @@ impl Archetype for Keep {
                             Branch {
                                 len: 0,
                                 attr: Attr {
-                                    storeys: 2,
+                                    storeys: storeys + rng.gen_range(1, 3),
                                     is_tower: true,
                                     ridged: false,
                                     rounded: true,
+                                    has_doors: false,
                                 },
                                 locus: 6 + rng.gen_range(0, 3),
                                 border: 3,
@@ -89,6 +93,17 @@ impl Archetype for Keep {
         let important_layer = normal_layer + 1;
         let internal_layer = important_layer + 1;
 
+        let make_meta = |ori| {
+            Rgb::new(
+                match ori {
+                    Ori::East => 0,
+                    Ori::North => 2,
+                },
+                0,
+                0,
+            )
+        };
+
         let make_block = |r, g, b| {
             BlockMask::new(
                 Block::new(BlockKind::Normal, Rgb::new(r, g, b)),
@@ -100,6 +115,10 @@ impl Archetype for Keep {
         let brick_tex = RandomField::new(0).get(brick_tex_pos) as u8 % 24;
         let foundation = make_block(80 + brick_tex, 80 + brick_tex, 80 + brick_tex);
         let wall = make_block(100 + brick_tex, 100 + brick_tex, 110 + brick_tex);
+        let window = BlockMask::new(
+            Block::new(BlockKind::Window1, make_meta(ori.flip())),
+            normal_layer,
+        );
         let floor = make_block(
             80 + (pos.y.abs() % 2) as u8 * 15,
             60 + (pos.y.abs() % 2) as u8 * 15,
@@ -132,23 +151,19 @@ impl Archetype for Keep {
             }
         };
 
-        let edge_pos = if (bound_offset.x.abs() > bound_offset.y.abs()) ^ (ori == Ori::East) {
-            pos.y
-        } else {
-            pos.x
-        };
-
+        let ridge_x = (center_offset.map(|e| e.abs()).reduce_min() + 2) % 8;
         let width = locus
-            + if (edge_pos + 1000) % 8 < 4 && attr.ridged && !attr.rounded {
+            + if ridge_x < 4 && attr.ridged && !attr.rounded {
                 1
             } else {
                 0
             };
         let rampart_width = 2 + width;
-        let storey_height = 16;
+        let storey_height = 9;
         let roof_height = attr.storeys * storey_height;
+        let storey_y = profile.y % storey_height;
         let door_height = 6;
-        let rampart_height = roof_height + if edge_pos % 2 == 0 { 3 } else { 4 };
+        let rampart_height = roof_height + if ridge_x % 2 == 0 { 3 } else { 4 };
         let min_dist = if attr.rounded {
             bound_offset.map(|e| e.pow(2) as f32).sum().powf(0.5) as i32
         } else {
@@ -158,24 +173,32 @@ impl Archetype for Keep {
         if profile.y <= 0 - (min_dist - width - 1).max(0) && min_dist < width + 3 {
             // Foundations
             foundation
-        } else if (0..=roof_height).contains(&profile.y) && profile.y % storey_height == 0 && min_dist < rampart_width {
+        } else if (0..=roof_height).contains(&profile.y) && storey_y == 0 && min_dist <= width + 1 {
             if min_dist < width { floor } else { wall }
-        } else if !attr.is_tower
-            && bound_offset.x.abs() == 4
-            && min_dist == width + 1
-            && profile.y < roof_height
-        {
-            wall
         } else if bound_offset.x.abs() < 3
             && profile.y < door_height - bound_offset.x.abs()
             && profile.y > 0
             && min_dist >= width - 2
+            && min_dist <= width + 1
+            && attr.has_doors
         {
             internal
-        } else if min_dist == width && profile.y <= roof_height {
-            wall
+        } else if (min_dist == width || (!attr.is_tower && min_dist == width + 1))
+            && profile.y <= roof_height
+        {
+            if attr.is_tower
+                && (3..7).contains(&storey_y)
+                && bound_offset.x.abs() < width - 2
+                && (5..7).contains(&ridge_x)
+            {
+                window
+            } else {
+                wall
+            }
         } else if profile.y >= roof_height {
-            if profile.y > roof_height && min_dist < rampart_width {
+            if profile.y > roof_height
+                && (min_dist < rampart_width - 1 || (attr.is_tower && min_dist < rampart_width))
+            {
                 if attr.is_tower && center_offset == Vec2::zero() && profile.y < roof_height + 16 {
                     pole
                 } else if attr.is_tower
@@ -189,7 +212,7 @@ impl Archetype for Keep {
                 } else {
                     empty
                 }
-            } else if min_dist == rampart_width {
+            } else if min_dist <= rampart_width {
                 if profile.y < rampart_height {
                     wall
                 } else {
@@ -203,15 +226,17 @@ impl Archetype for Keep {
         } else {
             empty
         }
-        .resolve_with(if attr.is_tower && profile.y > 0 && profile.y <= roof_height {
-            make_staircase(
-                Vec3::new(center_offset.x, center_offset.y, pos.z),
-                7.0f32.min(width as f32 - 1.0),
-                0.5,
-                9.0,
-            )
-        } else {
-            BlockMask::nothing()
-        })
+        .resolve_with(
+            if attr.is_tower && profile.y > 0 && profile.y <= roof_height {
+                make_staircase(
+                    Vec3::new(center_offset.x, center_offset.y, pos.z),
+                    7.0f32.min(width as f32 - 1.0),
+                    0.5,
+                    9.0,
+                )
+            } else {
+                BlockMask::nothing()
+            },
+        )
     }
 }