let defaultMagicItemInfo = {
upgradeTo : string option
upgradeFrom : string option
let defaultCostImpacts = {
type Terrain = Water | Land
type BuildingType = Empty | House
| Building of BuildingType * int
buildingType : BuildingType
items : MagicItemInfo option
upgrades : Upgrades option
impacts : CostImpacts option
constraints : Constraint list
let createBuilding name size bpCost e l s f def value =
cost = {defaultCost with bp = bpCost}
bonuses = {defaultBonuses with economy = e; loyalty = l; stability = s; fame = f; defense = def; addedValue = value}
type ConstructedBuilding = {
buildings : ConstructedBuilding list
terrain : (Position * Terrain) list
let addBonuses (acc:Bonuses) (bonus:Bonuses) =
economy = acc.economy + bonus.economy
defense = acc.defense + bonus.defense
addedValue = acc.addedValue + bonus.addedValue
fame = acc.fame + bonus.fame
loyalty = acc.loyalty + bonus.loyalty
stability = acc.stability + bonus.stability
let sumCityBonuses (city: CityGrid) =
|> List.map (fun building -> building.def.bonuses)
|> List.fold addBonuses defaultBonuses
sumCityBonuses a > sumCityBonuses b
let isWithinWalls size pos =
pos.row <= size && pos.row >= 0 && pos.col <= size && pos.col >= 0
let sumBuildingsWithType (buildings:BuildDef list) t =
|> List.filter (fun b -> b.buildingType = t)
let getTerrainAtPos pos city =
|> List.tryFind (fun (p, t) -> pos = p)
let getBuildingAtPos pos city =
|> List.tryFind ( fun b -> b.pos = pos)
let evalConstraint (city:CityGrid) (limit:Constraint) (pos:Position) =
let buildings = city.buildings |> List.map (fun n -> n.def)
let destBuilding = getBuildingAtPos pos city
| None -> failwith "no building at that pos"
| Some t -> t.buildingType
| Building (t, n) -> (sumBuildingsWithType buildings t) > n
| TotalCount n -> (sumBuildingsWithType buildings destBuildingType) > n
match (getTerrainAtPos pos city) with
let meetsConstraints city (building:BuildDef) pos =
|> List.fold (fun acc con -> acc && evalConstraint city con pos) true
let addBuilding city building name pos =
if not (isWithinWalls city.sideLength pos) then failwith "not enough size"
if (getBuildingAtPos pos city).IsSome then failwith "position already occupied"
if not (meetsConstraints city building pos) then failwith "doesn't meet constraints"
city.buildings @ [constructed]