001 (ns cc.journeyman.the-great-game.buildings.rectangular
002 "Build buildings with a generally rectangular floow plan.
003
004 ## Motivations
005
006 Right, the idea behind this namespace is many fold.
007
008 1. To establish the broad principle of genetic buildings, by creating a
009 function which reproducibly creates reproducible buildings at specified
010 locations, such that different buildings are credibly varied but a
011 building at a specified location is always (modulo economic change) the
012 same.
013 2. Create good rectangular buildings, and investigate whether a single
014 function can be used to create buildings of more than one family (e.g.
015 can it produce flat roofed, north African style, mud brick houses as
016 well as pitch roofed, half timbered northern European houses?)
017 3. Establish whether, in my current state of fairly severe mental illness,
018 I can actually produce any usable code at all.
019
020 ## Key factors in the creation of a building
021
022 ### Holding
023
024 Every building is on a holding, and, indeed, what I mean by 'building' here
025 may well turn out to be 'the collection of all the permanent structures on
026 a holding. A holding is a polygonal area of the map which does not
027 intersect with any other holding, but for the time being we'll make the
028 simplifying assumption that every holding is a rectangular strip, and that
029 'urban' holdings are of a reasonably standard width (see Viking-period
030 York) and length. Rural holdings (farms, ?wood lots) may be much larger.
031
032 ### Terrain
033
034 A building is made of the stuff of the place. In a forest, buildings will
035 tend to be wooden; in a terrain with rocky outcrops -- normally found on
036 steep slopes -- stone. On the flat lands where there's river mud, of brick,
037 cob, or wattle and daub. So to build a building we need to know the
038 terrain. Terrain can be inferred from location but in practice this will
039 be computationally expensive, so we'll pass terrain in as an argument to
040 the build function.
041
042 For the time being we'll pass it in simply as a keyword from a defined set
043 of keywords; later it may be a more sophisticated data structure.
044
045 ### Culture
046
047 People of different cultures build distinctively different buildings, even
048 when using the same materials. So, in our world, a Japanese wooden house
049 looks quite different from an Anglo Saxon stave house which looks quite
050 different from a Canadian log cabin, even though the materials are much the
051 same and the tools available to build with are not much different.
052
053 Culture can affect not just the overall shape of a building but also its
054 finish and surface detail. For example, in many places in England, stone
055 buildings are typically left bare; in rural Scotland, typically painted
056 white or in pastel shades; in Ireland, often quite vivid colours.
057
058 People may also show religious or cultural symbols on their buildings.
059
060 For all these reasons, we need to know the culture of the occupant when
061 creating a building. Again, this will initially be passed in as a keyword.
062
063 ### Craft
064
065 People in the game world have a craft, and some crafts will require
066 different features in the building. In the broadly late-bronze-age-to
067 medieval period within which the game is set, residence and workplace
068 are for most people pretty much the same.
069
070 So a baker needs an oven, a smith a forge, and so on. All crafts who do
071 some degree retail trade will want a shop front as part of the ground
072 floor of their dwelling. Merchants and bankers will probably have houses
073 that are a bit more showy than others.
074
075 Whether the 'genetic buildings' idea will ever really produce suitable
076 buildings for aristons I don't know; it seems more likely that significant
077 strongholds (of which there will be relatively few) should all be hand
078 modelled rather than procedurally generated."
079 (:require [cc.journeyman.the-great-game.holdings.holding :refer [ProtoHolding]]
080 [cc.journeyman.the-great-game.location.location :refer [ProtoLocation]])
081 (:import [org.apache.commons.math3.random MersenneTwister]))
082
083
084 (def ^:dynamic *terrain-types*
085 "Types of terrain which affect building families. TODO: This is a placeholder;
086 a more sophisticated model will be needed."
087 #{:arable :arid :forest :plateau :upland})
088
089 (def ^:dynamic *cultures*
090 "Cultures which affect building families. TODO: placeholder"
091 #{:ariston :coastal :steppe-clans :western-clans :wild-herd})
092
093 (def ^:dynamic *crafts*
094 "Crafts which affect building types in the game. See
095 `Populating a game world`. TODO: placeholder"
096 #{:baker :banker :butcher :chancellor :innkeeper :lawyer :magus :merchant :miller :priest :scholar :smith :weaver})
097
098 (def ^:dynamic *building-families*
099 "Families of buildings.
100
101 Each family has
102
103 * terrain types to which it is appropriate;
104 * crafts to which it is appropriate;
105 * cultures to which it is appropriate.
106
107 Each generated building will be of one family, and will comprise modules
108 taken only from that family."
109 {:pitched-rectangular {:terrains #{:arable :forest :upland}
110 :crafts *crafts*
111 :cultures #{:coastal :western-clans}
112 :modules []}
113 :flatroof-rectangular {:terrains #{:arid :plateau}
114 :crafts *crafts*
115 :cultures #{:coastal}
116 :modules []}})
117
118 ;; TODO: So, modules need to contain
119 ;;
120 ;; 1. Ground floor modules, having external doors;
121 ;; 2. Craft modules -- workshops -- which will normally be ground floor (except
122 ;; weavers) and may have the constraint that no upper floor module can cover them;
123 ;; 3. Upper floor modules, having NO external doors (but linking internal doors);
124 ;; 4. Roof modules
125 ;;
126 ;; There also needs to be an undercroft or platform module, such that the area of
127 ;; the top of the platform is identical with the footprint of the building, and
128 ;; the altitude of the top of the platform is equal to the altitude of the
129 ;; terrain at the heighest corner of the building; so that the actual
130 ;; building doesn't float in the air, and also so that none of the doors or windows
131 ;; are partly underground.
132 ;;
133 ;; Each module needs to wrap an actual 3d model created in Blender or whatever,
134 ;; and have a list of optional textures with which that model can be rendered.
135 ;; So an upper floor bedroom module might have the following renders:
136 ;;
137 ;; 1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture
138 ;; 2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture
139 ;; 3. Half-timbered - not available on plateau terrain
140 ;; 4. Weatherboarded - constrained to forest terrain
141 ;; 5. Brick - constrained to arable or arid terrain
142 ;;
143 ;; of course these are only examples, and also, it's entirely possible to have
144 ;; for example multiple different weatherboard renders for the same module.
145 ;; There needs to be a way of rendering what can be built above what: for
146 ;; example, you can't have a masonry clad module over a half timbered one,
147 ;; but you can have a half-timbered one over a masonry one
148
149 (defn building-family
150 "A building family is essentially a collection of models of building modules
151 which can be assembled to create buildings of a particular structural and
152 architectural style."
153 [terrain culture craft gene]
154 (let [candidates (filter #(and
155 ((:terrains %) terrain)
156 ((:crafts %) craft)
157 ((:cultures %) culture))
158 (vals *building-families*))]
159 (nth candidates (mod (Math/abs (.nextInt gene)) (count candidates)))))
160
161 (building-family :arable :coastal :baker (MersenneTwister. 5))
162
163 (defn build!
164 "Builds a building, and returns a data structure which represents it. In
165 building the building, it adds a model of the building to the representation
166 of the world, so it does have a side effect."
167 [holding terrain culture craft size]
168 (if (satisfies? ProtoHolding holding)
169 (let [location (.building-origin holding)
170 gene (MersenneTwister. (int (+ (* (.easting location) 1000000) (.northing location))))
171 family (building-family terrain culture craft gene)]
172 (if
173 (and (instance? ProtoLocation location) (:orientation location))
174 :stuff
175 :nonsense
176 ))
177 :froboz))
178
179 ;; (def ol (cc.journeyman.the-great-game.location.location/OrientedLocation. 123.45 543.76 12.34 0.00 {}))
180