1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
namespace LivingVillage.Desktop
module TitleScreen =
type ColorRgb =
{ R: int
G: int
B: int }
type TitleLayout =
{ SkyBands: ColorRgb list
RoofTileSlots: int list
RidgeY: int
EaveY: int
WaterRows: int list
Lanterns: (int * int) list
TitleText: string
TitleX: int
TitleY: int
TitleScale: int
MenuX: int
MenuTopY: int
MenuLineHeight: int
PanelX: int
PanelY: int
PanelWidth: int
PanelHeight: int
HeadingY: int
FirstItemY: int
CursorX: int
CursorWidth: int
TextX: int }
type TextRect =
{ X: int
Y: int
Width: int
Height: int }
let rectsDisjoint (a: TextRect) (b: TextRect) : bool =
a.X + a.Width <= b.X
|| b.X + b.Width <= a.X
|| a.Y + a.Height <= b.Y
|| b.Y + b.Height <= a.Y
/// Cursor and label rectangles for one menu row. The cursor is drawn in its own
/// column; the label always starts to the right of it, so they can never overprint.
let selectionRects (layout: TitleLayout) (rowIndex: int) : TextRect * TextRect =
let y = layout.FirstItemY + rowIndex * layout.MenuLineHeight
{ X = layout.CursorX; Y = y; Width = layout.CursorWidth; Height = 16 },
{ X = layout.TextX; Y = y; Width = layout.PanelX + layout.PanelWidth - layout.TextX - 24; Height = 16 }
// Palette mirrors the VillageArt atlas: roof (45,49,57)/(30,33,38), water (54,116,145),
// lantern paper (212,92,74). Purely decorative reuse of existing art colors.
let private skyBands : ColorRgb list =
[ { R = 16; G = 26; B = 42 }
{ R = 20; G = 36; B = 52 }
{ R = 24; G = 46; B = 62 }
{ R = 28; G = 56; B = 68 }
{ R = 32; G = 64; B = 72 } ]
let private roofRidgeSlot = 8
let private roofEaveSlot = 9
let private waterTileSlot = 1
let private lanternColor = { R = 212; G = 92; B = 74 }
let private lanternHalo = { R = 252; G = 216; B = 148 }
let lanternColors : ColorRgb * ColorRgb = lanternColor, lanternHalo
let skyBandCount = skyBands.Length
let waterSlot = waterTileSlot
let roofSlots = roofRidgeSlot, roofEaveSlot
let layout (viewportWidth: int) (viewportHeight: int) : TitleLayout =
let width = max 320 viewportWidth
let height = max 240 viewportHeight
let tilePixels = 32
let columns = width / tilePixels
let roofTileSlots =
[ 0 .. columns - 1 ]
|> List.map (fun column ->
if column % 4 = 0 || column % 7 = 3 then roofRidgeSlot else roofEaveSlot)
let waterRows =
[ height - 96
height - 64 ]
let lanternCount = max 3 (columns / 10)
let lanterns =
[ 1 .. lanternCount ]
|> List.map (fun index ->
let x = index * width / (lanternCount + 1)
let y = (List.head waterRows) - 44 + (if index % 2 = 0 then 12 else 0)
x, y)
let panelWidth = min 460 (width - 64)
{ SkyBands = skyBands
RoofTileSlots = roofTileSlots
RidgeY = 44
EaveY = 76
WaterRows = waterRows
Lanterns = lanterns
TitleText = "江南水乡"
TitleX = (width - 4 * (4 * 16)) / 2
TitleY = 120
TitleScale = 4
MenuX = (width - panelWidth) / 2 + 40
MenuTopY = height / 2 - 40
MenuLineHeight = 30
PanelX = (width - panelWidth) / 2
PanelY = height / 2 - 64
PanelWidth = panelWidth
PanelHeight = min 360 (height - height / 2 - 40)
HeadingY = height / 2 - 64 + 20
FirstItemY = height / 2 - 64 + 60
CursorX = (width - panelWidth) / 2 + 24
CursorWidth = 20
TextX = (width - panelWidth) / 2 + 24 + 20 + 12 }
|