-
Notifications
You must be signed in to change notification settings - Fork 0
/
DataConverter.fs
240 lines (213 loc) · 7.71 KB
/
DataConverter.fs
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
module DataConverter
open System
open Types
open Tilesets
let private exportActor (id, actor) =
let {Name = name; ControllerName = controller} = actor
let script =
match actor.Script with
| WaitScript -> "waitAI"
| StandGround -> "standgroundAI"
| DumbHunt -> "dumbhuntAI"
[
string id
name
string (defaultTilesetParser.CombatActorParser actor.Tile)
controller
script
]
|> List.toSeq
|> String.concat ";"
let private importActor (str: string) =
let vals = Array.toList (str.Split ";")
match vals with
| [id; name; tile; controllerName; script] ->
int id,
{
Tile = getActorTile (char tile)
ControllerName = controllerName
Name = name
Script =
match script with
| "waitAI" -> WaitScript
| "standgroundAI" -> StandGround
| "dumbhuntAI" -> DumbHunt
| _ -> failwith ("invalid actor: unrecognised AI: " + script)
}
| _ -> failwith ("invalid actor: wrong length: " + str)
let private exportController (name, {Type = t; Colour = c}) =
let ts =
match t with
| Player -> "player"
| AIController -> "ai"
name + ";" + ts + ";" + string c
let private importController (str: string) =
let tokens = str.Split ';' |> Array.toList
match tokens with
| []
| [_]
| [_; _] ->
failwith "invalid controller: too few parameters"
| _ :: _ :: _ :: _ :: _ ->
failwith "invalid controller: too many parameters"
| [n; t; c] ->
let controllerType =
match t with
| "player" -> Player
| "ai" -> AIController
| _ -> failwithf "invalid controller: unrecognised type: %s" t
match Enum.TryParse<ConsoleColor>(c) with
| false, _ ->
failwithf "invalid controller: unrecognised colour: %s" c
| true, colour ->
n, {Type = controllerType; Colour = colour}
let private pushControllers controllers stream =
let nControllers = Map.count controllers
stream @ (string nControllers :: List.map exportController (Map.toList controllers))
let private popControllers (stream: string list) =
let nControllers = int stream.[0]
List.map importController stream.[1..nControllers] |> Map.ofList, stream.[(nControllers + 1)..]
let private exportControllerRelation ((c1, c2), r) =
c1 + ";" + c2 + ";" + string r
let private importControllerRelation (str: string) =
let tokens = str.Split ';' |> Array.toList
match tokens with
| []
| [_]
| [_; _] ->
failwith "invalid controller relation: too few parameters"
| _ :: _ :: _ :: _ :: _ ->
failwith "invalid controller relation: too many parameters"
| [c1; c2; r] ->
match r with
| "SameController" ->
(c1, c2), SameController
| "Enemy" ->
(c1, c2), Enemy
| _ ->
failwithf "invalid controller relation: unrecognised relation: %s" r
let private pushControllerRelations controllerRelations stream =
let nControllerRelations = Map.count controllerRelations
stream @ (string nControllerRelations :: List.map exportControllerRelation (Map.toList controllerRelations))
let private popControllerRelations (stream: string list) =
let nControllerRelations = int stream.[0]
List.map importControllerRelation stream.[1..nControllerRelations] |> Map.ofList, stream.[(nControllerRelations + 1)..]
let private pushActors actors stream =
let a = Map.toList actors
let nActors = List.length a
stream @ (string nActors :: List.map exportActor a)
let private popActors (stream: string list) =
let nActors = int stream.[0]
(
List.map importActor stream.[1..nActors]
|> Map.ofList,
stream.[(nActors + 1)..]
)
let exportActorID = string
let importActorID = int
let private pushActorCombatQueue actorCombatQueue stream =
let nActors = List.length actorCombatQueue
stream @ (string nActors :: List.map exportActorID actorCombatQueue)
let private popActorCombatQueue (stream: string list) =
let nActors = int stream.[0]
(List.map importActorID stream.[1..nActors], stream.[(nActors + 1)..])
let exportActorPosition (id, {X = x; Y = y}) =
[id; x; y]
|> List.map string
|> List.toSeq
|> String.concat " "
let importActorPosition (str: string) =
let tokens =
str.Split " "
|> Array.toList
|> List.map int
tokens.[0], {X = tokens.[1]; Y = tokens.[2]}
let private pushActorCombatPositions actorPositions stream =
let ap = Map.toList actorPositions
let nActors = List.length ap
stream @ (string nActors :: List.map exportActorPosition ap)
let private popActorCombatPositions (stream: string list) =
let nActors = int stream.[0]
(
List.map importActorPosition stream.[1..nActors]
|> Map.ofList,
stream.[(nActors + 1)..]
)
let private exportMapTiles tiles =
convertMapTilesToString defaultTilesetParser.CombatMapParser tiles
let importMapTiles (tiles: string) =
tiles
|> Seq.toList
|> List.map getMapTile
let private pushMap map stream =
let tiles =
map.Tiles
|> Map.toList
|> List.sortBy (fun ({X = x; Y = y}, _) -> (y, x))
|> List.map (fun (_, tile) -> tile)
stream @ [
string map.Width
string map.Height
]
@ List.singleton (exportMapTiles tiles)
let private popMap (stream: string list) =
let width = int stream.[0]
let height = int stream.[1]
let tiles = importMapTiles stream.[2]
let map = CombatMap.create width height tiles
(map, stream.[3..])
let private pushRest statusBar (tileset: Tileset) (stream: string list) =
stream @ [
string statusBar.Start.X
string statusBar.Start.Y
string statusBar.Length
string tileset
]
let exportGameState combatState tileset statusState =
let {
CombatMap = map
Actors = actors
ActorCombatQueue = actorCombatQueue
ActorCombatPositions = actorCombatPositions
Controllers = controllers
ControllerRelations = controllerRelations
} = combatState
let {StatusBar = statusBar} = statusState
[]
|> pushControllers controllers
|> pushControllerRelations controllerRelations
|> pushActors actors
|> pushActorCombatQueue actorCombatQueue
|> pushActorCombatPositions actorCombatPositions
|> pushMap map
|> pushRest statusBar tileset
let importGameState (stream: string list) =
let (controllers, relationsFirst) = popControllers stream
let (controllerRelations, actorsFirst) = popControllerRelations relationsFirst
let (actors, queueFirst) = popActors actorsFirst
let (actorCombatQueue, positionsFirst) = popActorCombatQueue queueFirst
let (actorCombatPositions, mapFirst) = popActorCombatPositions positionsFirst
let (map, rest) = popMap mapFirst
let combatState = {
Actors = actors
ActorCombatQueue = actorCombatQueue
ActorCombatPositions = actorCombatPositions
CombatMap = map
Controllers = controllers
ControllerRelations = controllerRelations
}
let statusState = {
StatusBar = {Start = {X = int rest.[0]; Y = int rest.[1]}; Length = int rest.[2]}
StatusBuffer = {Receiver = "player"; Stream = ""}
}
let tileset =
match rest.[3] with
| "DefaultTileset" -> DefaultTileset
| "DottedTileset" -> DottedTileset
| _ -> DefaultTileset
let startResult =
match rest.[3] with
| "DefaultTileset" -> NormalStart
| "DottedTileset" -> NormalStart
| _ -> StartWithUnknownTileset
combatState, tileset, statusState, startResult