diff options
Diffstat (limited to 'src/LivingVillage.Desktop/MapGen.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/MapGen.fs | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/src/LivingVillage.Desktop/MapGen.fs b/src/LivingVillage.Desktop/MapGen.fs index 63b14bc..ce9fb3a 100644 --- a/src/LivingVillage.Desktop/MapGen.fs +++ b/src/LivingVillage.Desktop/MapGen.fs @@ -34,7 +34,9 @@ module MapGen = /// P24:大图额外沿河民居数量(沿现有路网泊松散布)。默认 0,64x48/256x192 不受影响。 ExtraRiversideHouses: int /// P25:是否放置孤立装饰石块。默认 true;大图关闭,避免草地上出现游离石板 tile。 - DecorativeStones: bool } + DecorativeStones: bool + /// P26:是否沿海河岸放置河岸装饰(护岸石垒/芦苇/垂柳)。默认 false;仅大图开启。 + RiverDecorations: bool } /// P20 第二步:一条贯穿全图的东西向河道(每列恰好一段,宽度下限 RiverWidth)。 type River = @@ -50,6 +52,18 @@ module MapGen = DoorX: int DoorY: int } + /// P26 河岸装饰种类:护岸石垒 / 芦苇 / 垂柳(垂柳占上下两格)。 + type RiverDecorationKind = + | RevetmentStone + | Reeds + | Willow + + /// P26 河岸装饰:纯视觉,不写入瓦片、不影响通行;仅大图沿海河岸生成。 + type RiverDecoration = + { Kind: RiverDecorationKind + X: int + Y: int } + type Result = { Width: int Height: int @@ -61,6 +75,7 @@ module MapGen = Bridges: (int * int) list Paths: (int * int) list Buildings: Building list + Decorations: RiverDecoration list ReachableTiles: int ReachabilityOk: bool BridgeCrossingsOk: bool } @@ -76,7 +91,8 @@ module MapGen = SpawnColumns = 5 SpawnRows = 6 ExtraRiversideHouses = 0 - DecorativeStones = true } + DecorativeStones = true + RiverDecorations = false } /// P23 尺寸自适应参数:河道数量随高度增长(约每 96 行一条),其余沿用默认。 /// 64x48 / 256x192 仍得到 2 条河道,与既有输出逐字节一致;512x384 得到 4 条。 @@ -89,7 +105,8 @@ module MapGen = Height = height RiverCount = max base_.RiverCount (max 1 (height / 96)) ExtraRiversideHouses = (if large then 10 else 0) - DecorativeStones = not large } + DecorativeStones = not large + RiverDecorations = large } // ---- splitmix64 与 value noise(无外部依赖、无时钟) ---- @@ -330,6 +347,63 @@ module MapGen = addPath building.DoorX building.DoorY extraPlaced <- extraPlaced + 1 + // 5c) P26:河岸装饰(护岸石垒/芦苇/垂柳),仅大图启用。纯视觉层,不写入任何瓦片, + // 故 64x48/256x192 的 tiles checksum 与默认世界完全不受影响;装饰只落在紧邻水面的 + // 岸格,且避开路网/桥面/民居/核心区,保证不遮挡通行。 + let mutable decorations: RiverDecoration list = [] + if p.RiverDecorations then + let mutable decorRng = p.Seed ^^^ 0xD3C0DEUL + let nextDecor () = + let nextState, raw = splitmix decorRng + decorRng <- nextState + raw + let bridgeLookup = System.Collections.Generic.HashSet<int>(bridges |> List.map (fun (x, y) -> idx x y)) + let inBuildingFootprint x y = + buildings + |> List.exists (fun b -> + x >= b.Left - 1 && x <= b.Left + b.Width && y >= b.Top && y <= b.DoorY + 1) + let blocked x y = + not (inMap x y) + || tiles.[idx x y] = int GroundTile.Water + || pathSet.Contains(idx x y) + || bridgeLookup.Contains(idx x y) + || inCore x y + || inBuildingFootprint x y + let occupies (kind: RiverDecorationKind) (y: int) = + if kind = Willow then [ y; y + 1 ] else [ y ] + let tooClose (kind: RiverDecorationKind) x y = + decorations + |> List.exists (fun d -> + let dyList = occupies d.Kind d.Y + occupies kind y + |> List.exists (fun cy -> + dyList + |> List.exists (fun oy -> + let dx = d.X - x + let dy = oy - cy + dx * dx + dy * dy < 9))) + let tryPlace (kind: RiverDecorationKind) x y = + let tilesFree = + if kind = Willow then not (blocked x y) && not (blocked x (y + 1)) + else not (blocked x y) + if tilesFree && not (tooClose kind x y) then + decorations <- { Kind = kind; X = x; Y = y } :: decorations + let kindOf (roll: uint64) = + match int (roll % 3UL) with + | 1 -> Reeds + | 2 -> Willow + | _ -> RevetmentStone + for river in riverBands do + for x in 2 .. w - 3 do + let lowerRoll = nextDecor () + if lowerRoll % 3UL <> 0UL then + tryPlace (kindOf lowerRoll) x (river.CenterY + river.Width) + if nextDecor () % 4UL = 0UL then + let upperRoll = nextDecor () + let kind = kindOf upperRoll + let anchorY = if kind = Willow then river.CenterY - 2 else river.CenterY - 1 + tryPlace kind x anchorY + // 6) 30 个 spawn:核心区内的规则网格。 let sc = max 2 p.SpawnColumns let sr = max 2 p.SpawnRows @@ -385,6 +459,7 @@ module MapGen = Bridges = bridges Paths = paths Buildings = buildings + Decorations = decorations ReachableTiles = reachableTiles ReachabilityOk = spawnsOk && doorsOk && bridgesOk BridgeCrossingsOk = crossingsOk } @@ -414,6 +489,16 @@ module MapGen = .Append(building.Width).Append(':').Append(building.Height).Append(':') .Append(building.DoorX).Append(':').Append(building.DoorY).Append(';') |> ignore + builder.Append('|') |> ignore + let decorCode = function + | RevetmentStone -> 0 + | Reeds -> 1 + | Willow -> 2 + for decoration in map.Decorations do + builder + .Append(decorCode decoration.Kind).Append(':') + .Append(decoration.X).Append(':').Append(decoration.Y).Append(';') + |> ignore builder.ToString() /// 可行走判定:非水,或位于桥面上(桥面仍标记为水但可通行)。 |
