diff --git a/.gitignore b/.gitignore index b0ebaf1..db35160 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ pom.xml.asc *.jar *.class *.log +*.stl [0-9a-f]*-init.clj /lib/ /classes/ @@ -18,4 +19,3 @@ pom.xml.asc .cpcache/ *~ -doc/.~lock.Population.ods# diff --git a/doc/Pathmaking.md b/doc/Pathmaking.md new file mode 100644 index 0000000..216446b --- /dev/null +++ b/doc/Pathmaking.md @@ -0,0 +1,114 @@ +# Pathmaking + +**NOTE**: this file is called 'pathmaking', not 'pathfinding', because 'pathfinding' has a very specific meaning/usage in game design which is only part of what I want to talk about here. + +## Stages in creating routes between locations + +### The 'procedural' phase + +*see also [[Baking-the-world]]* + +Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days. + +At the start of the baking phase, routes - roads, tracks and paths - designed by the game designers already exist. + +The algorithmic part of choosing a route is the same during this baking phase as in actual game play **except** that during the baking phase the routemap is being dynamically updated, creating a new path or augmenting an existing path wherever any agent goes. + +Thus the 'weight' of any section of route is a function of the total number of times that route segment has been traversed by an agent during this baking phase. At the end of the baking phase, routes travelled more than `R` times are rendered as roads, `T` times as tracks, and `P` times as footpaths, where `R`, `T` and `P` are all chosen by the game designer but generally `R > T > P`. + +### Algorithmic rules + +1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won't render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled; +2. No route may pass through any building, with the exception of a city gate; +3. We don't have bicycles: going uphill costs work, and you don't get that cost back on the down hill. Indeed, downhills are at least as expensive to traverse as flat ground; +4. Any existing route segment costs only a third as much to traverse as open ground having the same gradient; +5. A more used route costs less to traverse than a less used route. + +### River crossings + +Crossing rivers is expensive - say five times as expensive as level open ground (but this will probably need tuning). Where a river is shallow enough, (i.e. where the amount of water passing is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it's deeper than that, a path crossing either isn't rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as `navigable`, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don't need to be individually designed. + +### Representation + +At some stage in the future I'll have actual game models to work with and $DEITY knows what the representation of those will be like, but to get this started I need two inputs: a heightmap, from which gradients can be derived, and a route map. The heightmap can conventionally be a monochrome raster image, and that's easy. The route map needs to be a vector representation, and SVG will be as convenient as any. So from the point of view of routing during the baking phase, a route map shall be an SVG with the following classes: + +* `exclusion` used on polygons representing e.g. buildings, or impassable terrain which may not be traversed at all; +* `openwater` used on polygons representing oceans and lakes, which may be traversed only by boat (or possibly swimming, for limited distances); +* `watercourse` used on paths representing rivers or streams, with some additional attribute giving rate of flow; +* `navigable` may be an additional class on a path also marked `watercourse` indicating that it is navigable by cargo vessels; +* `route` used on paths representing a path, track or road whose final representation will be dynamically assigned at the end of baking, with some additional attribute giving total traversals to date; +* `path` used on paths representing a path designed by the designers, which will certainly be rendered as a path no matter how frequently it is traversed; +* `track` used on paths representing a track designed by the designers, which will certainly be rendered as a track no matter how frequently it is traversed; +* `road` used on paths representing a road designed by the designers, which will certainly be rendered as a road no matter how (in)frequently it is traversed. + +At the end of the baking process the routing engine should be able to write out an updated SVG. New routes should be splined curves, so that they have natural bends not sharp angles. + +### The 'Walkmap' + +Conventional game pathfinding practice is to divide the traversable area into a mesh of 'convex polygons', where a 'convex polygon' in this sense is, essentially, a polygon having no bays. Routes traverse from a starting point to the centre of a polygon ajacent to the polygon in which the starting point is located. I have reservations as to whether this will do what I need since I'm not convinced it will produce naturalistic paths; however, it's worth at least experimenting with. + +There are existing utilities (such as [hmm](https://github.com/fogleman/hmm)) which convert heightmaps into suitable geometry files; however all I've found so far convert to [binary STL](https://en.wikipedia.org/wiki/STL_(file_format)). This isn't a format I find very useful; I'd prefer an XML dialect, and SVG is good enough for me. + +`hmm` converts the heightmap into a tesselation of triangles, which are necessarily convex in the sense given above. Utilities (such as [binary-stl-toASCII](https://github.com/IsseiMori/binary-stl-toASCII)) exist to convert binary STL to an ASCII encoded equivalent, which may be easier to parse. + +So the pipeline seems to be + +1. heightmap to binary STL +2. (optional) binary STL to ASCII STL +3. STL to SVG (where 'SVG' here is shorthand for a convenient vector format) +4. Exclude holdings, buildings, open water, and other exclusions +5. Where we have excluded exclusions, ensure that any non-convex polygons we've created are divided into new convex polygons. + +I shall have to write custom code for 4 and 5 above, and, looking at what's available, probably 3 as well. + +I'm working on a separate library, [walkmap](https://simon-brooke.github.io/walkmap/), which will attempt to implement this pipeline. + +### Pathmaking and scale + +Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive. Just converting a 1000x1000 heightmap from STL to SVG is currently taking 8 hours and 15 minutes; and it ends up with a 46 megabyte SVG file! However, most of the time cost is in writing. Reading the STL file takes four and a quarter seconds; converting that STL to SVG in memory takes less than five seconds. So the huge cost is writing the file with Dali. + + walkmap.core=> (time (def stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl"))) + "Elapsed time: 4285.231513 msecs" + #'walkmap.core/stl + walkmap.core=> (time (def svg (stl-to-svg stl))) + "Elapsed time: 4865.798059 msecs" + #'walkmap.core/svg + + +"Elapsed time: 2.969569560662E7 msecs" + +We cannot effectively do routing at metre scale - which is what we ultimately need in settlements - across the entire thousand kilometre square map in one pass. But also we don't need to because much of the continent is by design relatively unpeopled and relatively untracked. The basic concept of the Steppe is that there are two north/south routes, the one over the Midnight Pass into the Great Place and the one via Hans'hua down to the Cities of the Coast, and those can be part of the 'designed roads' map. So we can basically exclude most of the Steppe from routing altogether. We can also - for equally obvious reasons exclude the ocean. The ocean makes up roughly half of the 1000x1000 kilometre map, the steppe and plateau take up half of what's left, mountain massifs eat into the remainder and my feeling is that much of the eastern part of the continent is probably too arid to be settled. So we probably end up only having to dynamically route about 20% of the entire map. + +However, this doesn't get round the main problem with scale, and pathmaking. If we pathmake at kilometre scale, then curves will be necessarily very long and sweeping - because each path segment will be at least a kilometre long. And, actually, that's fine for very long distance roads in unpopulated fairly flat territory. It's not so good for long distance roads in rugged terrain, but... + +#### Phase one: hand-designed routes + +While, given the bottlenecks of the few mountain passes and the one possible pass over the plateau, the caravan routes we want would almost certainly emerge organically out of dynamic routing. But, actually, I know more or less where they need to be and it's probably easiest to hand design them. It will certainly save an enormous amount of brute-force compute time. + +I think I have to accept that if I want Alpe d'Huez-style switchbacks up the Sunset and Midnight passes, they're going to have to be hand designed. The same applies to where the Hans'hua caravan road ascends the plateau. + +#### Phase two: route segments 'for free' out of settlement activity + +If we start by pathmaking around settlements, we can make a first start by giving the template for a holding a segment of track parallel to and just in front of its frontage, and a segment of path along its left hand and rear edges. That, actually, is going to provide 90% of all routing within a settlement, and it's done for us within the [[Settling-a-game-world]] phase. + +#### Phase three: metre scale routing around settlements + +So if we then collect groups of contiguous 100x100 metre zones each of which has at least one settled holding, we can route at one metre scale over that and what it will essentially do is join up and augment the route segments generated by settlement. Areas of dense settlement do not make up a great deal of the map. Note that experience may show that the metre scale routing is superflous. + +#### Phases four, five and six: increasing granularity + +Taking the augmented route map comprised of + +1. The hand-designed, mainly long distance or plot-important routes; +2. The route segments bordering holdings; +3. The metre scale routing + +we can then collect contiguous groups of zones each having at least one holding, where in phase four each zone is a kilometre square and divided into 100x100 grid so that we route at ten metre scale; in phase five we use ten kilometre by ten kilometre zones and we route at 100 metre scale; in phase six, 100 km by 100 km zones and we route at kilometre scale. This process should automatically link up all settlements on the south and west coasts, all those on the north coast, and all in the Great Place; and seeing that the posited pre-designed caravan roads already join the south coast to the north, the north to the Great Place and the Great Place to the south coast, we're done. + +At least one of phases three, four, five and six is probably redundant; but without trying I'm not sure which. + +### Tidying up + +After the full set of increasing-scale passes is complete, we should automatically cull any route segments generated in the settlement phase which have never actually been traversed. + +Following that, there may be scope for some final manual tweaking, if desired; I think this is most likely to happen where roads routed at kilometre scale cross rugged terrain. diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html index 516511b..929e2e6 100644 --- a/docs/cloverage/index.html +++ b/docs/cloverage/index.html @@ -17,13 +17,13 @@ the-great-game.agent.agent
1
+ float:left;"> 2 100.00 %
1
+ float:left;"> 2 100.00 % -721 +4352 the-great-game.gossip.gossip
38
92.73 %
91
9
4
-96.15 % -24630104 + style="width:88.07339449541284%; + float:left;"> 96
8
5
+95.41 % +25631109 the-great-game.merchants.markets
4.03 % 1736124 + + the-great-game.objects.container
2
+100.00 % +
2
+100.00 % +1112 + + + the-great-game.objects.game-object
3
2
+60.00 % +
3
2
+60.00 % +1925 + the-great-game.time
-66.88 % +66.90 % -68.59 % +68.74 % diff --git a/docs/cloverage/the_great_game/agent/agent.clj.html b/docs/cloverage/the_great_game/agent/agent.clj.html index bbdf18f..14d5821 100644 --- a/docs/cloverage/the_great_game/agent/agent.clj.html +++ b/docs/cloverage/the_great_game/agent/agent.clj.html @@ -8,22 +8,130 @@ 001  (ns the-great-game.agent.agent
- 002    "Anything in the game world with agency") + 002    "Anything in the game world with agency" +
+ + 003    (:require [the-great-game.objects.game-object :refer [ProtoObject]] +
+ + 004              [the-great-game.objects.container :refer [ProtoContainer]]))
- 003   + 005  
- 004  ;;  hierarchy of needs probably gets implemented here + 006  ;;  hierarchy of needs probably gets implemented here
- 005  ;;  I'm probably going to want to defprotocol stuff, to define the hierarchy + 007  ;;  I'm probably going to want to defprotocol stuff, to define the hierarchy
- 006  ;;  of things in the gameworld; either that or drop to Java, wich I'd rather not do. + 008  ;;  of things in the gameworld; either that or drop to Java, wich I'd rather not do.
- 007   + 009   +
+ + 010  (defprotocol ProtoAgent +
+ + 011    "An object which can act in the world" +
+ + 012    (act +
+ + 013      [actor world circle] +
+ + 014         "Allow `actor` to do something in this `world`, in the context of this +
+ + 015         `circle`; return the new state of the actor if something was done, `nil` +
+ + 016         if nothing was done. Circle is expected to be one of +
+ + 017   +
+ + 018         * `:active` - actors within visual/audible range of the player +
+ + 019           character; +
+ + 020         * `:pending` - actors not in the active circle, but sufficiently close +
+ + 021           to it that they may enter the active circle within a short period; +
+ + 022         * `:background` - actors who are active in the background in order to +
+ + 023           handle trade, news, et cetera; +
+ + 024         * `other` - actors who are not members of any other circle, although +
+ + 025           I'm not clear whether it would ever be appropriate to invoke an +
+ + 026           `act` method on them. +
+ + 027   +
+ + 028         The `act` method *must not* have side effects; it must *only* return a +
+ + 029         new state. If the actor's intention is to seek to change the state of +
+ + 030         something else in the game world, it must add a representation of that +
+ + 031         intention to the sequence which will be returned by its +
+ + 032         `pending-intentions` method.") +
+ + 033    (pending-intentions +
+ + 034      [actor] +
+ + 035      "Returns a sequence of effects an actor intends, as a consequence of +
+ + 036      acting. The encoding of these is not yet defined.")) +
+ + 037   +
+ + 038  ;; (defrecord Agent +
+ + 039  ;;   "A default agent." +
+ + 040  ;;   ProtoObject +
+ + 041  ;;   ProtoContainer +
+ + 042  ;;   ProtoAgent +
+ + 043  ;; )
diff --git a/docs/cloverage/the_great_game/gossip/news_items.clj.html b/docs/cloverage/the_great_game/gossip/news_items.clj.html index 6e5f68b..b2e762e 100644 --- a/docs/cloverage/the_great_game/gossip/news_items.clj.html +++ b/docs/cloverage/the_great_game/gossip/news_items.clj.html @@ -134,337 +134,337 @@ 043  
- 044    ##### Locations: + 044    By implication, the character values passed should include *all* the +
+ + 045    information the giver knows about the character; that can then be degraded +
+ + 046    as the receiver stores only that segment which the receiver finds +
+ + 047    interesting.
- 045   + 048  
- 046    A 'location' value is a list comprising at most the x/y coordinate location -
- - 047    and the ids of the settlement and region (possibly hierarchically) that contain -
- - 048    the location. If the x/y is not local to the home of the receiving agent, they -
- - 049    won't remember it and won't pass it on; if any of the ids are not interesting -
- - 050    So location information will degrade progressively as the item is passed along. + 049    ##### Locations:
- 051   + 050  
- 052    It is assumed that the `:home` of a character is a location in this sense. + 051    A 'location' value is a list comprising at most the x/y coordinate location +
+ + 052    and the ids of the settlement and region (possibly hierarchically) that contain +
+ + 053    the location. If the x/y is not local to the home of the receiving agent, they +
+ + 054    won't remember it and won't pass it on; if any of the ids are not interesting +
+ + 055    So location information will degrade progressively as the item is passed along.
- 053   + 056  
- 054    ##### Inferences: + 057    It is assumed that the `:home` of a character is a location in this sense.
- 055   + 058  
- 056    If an agent learns that Adam has married Betty, they can infer that Betty has + 059    ##### Inferences: +
+ + 060  
- 057    married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. + 061    If an agent learns that Adam has married Betty, they can infer that Betty has
- 058    I'm not convinced that my representation of inferences here is ideal. + 062    married Adam; if they learn that Charles killed Dorothy, that Dorothy has died.
- 059    " + 063    I'm not convinced that my representation of inferences here is ideal. +
+ + 064    "
- 060    { ;; A significant attack is interesting whether or not it leads to deaths + 065    { ;; A significant attack is interesting whether or not it leads to deaths
- 061      :attack {:verb :attack :keys [:actor :other :location]} + 066      :attack {:verb :attack :keys [:actor :other :location]}
- 062      ;; Deaths of characters may be interesting + 067      ;; Deaths of characters may be interesting
- 063      :die {:verb :attack :keys [:actor :location]} + 068      :die {:verb :die :keys [:actor :location]}
- 064      ;; Deliberate killings are interesting. + 069      ;; Deliberate killings are interesting.
- 065      :kill {:verb :kill :keys [:actor :other :location] + 070      :kill {:verb :kill :keys [:actor :other :location]
- 066             :inferences [{:verb :die :actor :other :other :nil}]} + 071             :inferences [{:verb :die :actor :other :other :nil}]}
- 067      ;; Marriages may be interesting + 072      ;; Marriages may be interesting
- 068      :marry {:verb :marry :keys [:actor :other :location] + 073      :marry {:verb :marry :keys [:actor :other :location]
- 069              :inferences [{:verb :marry :actor :other :other :actor}]} + 074              :inferences [{:verb :marry :actor :other :other :actor}]}
- 070      ;; The end of ongoing open conflict between to characters may be interesting + 075      ;; The end of ongoing open conflict between to characters may be interesting
- 071      :peace {:verb :peace :keys [:actor :other :location] + 076      :peace {:verb :peace :keys [:actor :other :location]
- 072              :inferences [{:verb :peace :actor :other :other :actor}]} + 077              :inferences [{:verb :peace :actor :other :other :actor}]}
- 073      ;; Things related to the plot are interesting, but will require special + 078      ;; Things related to the plot are interesting, but will require special
- 074      ;; handling. Extra keys may be required by particular plot events. + 079      ;; handling. Extra keys may be required by particular plot events.
- 075      :plot {:verb :plot :keys [:actor :other :object :location]} + 080      :plot {:verb :plot :keys [:actor :other :object :location]}
- 076      ;; Rapes are interesting. + 081      ;; Rapes are interesting.
- 077      :rape {:verb :rape :keys [:actor :other :location] + 082      :rape {:verb :rape :keys [:actor :other :location]
- 078             ;; Should you also infer from rape that actor is male and adult? + 083             ;; Should you also infer from rape that actor is male and adult?
- 079             :inferences [{:verb :attack} + 084             :inferences [{:verb :attack}
- 080                          {:verb :sex} + 085                          {:verb :sex}
- 081                          {:verb :sex :actor :other :other :actor}]} + 086                          {:verb :sex :actor :other :other :actor}]}
- 082      ;; Merchants, especially, are interested in prices in other markets + 087      ;; Merchants, especially, are interested in prices in other markets
- 083      :sell {:verb :sell :keys [:actor :other :object :location :price]} + 088      :sell {:verb :sell :keys [:actor :other :object :location :price]}
- 084      ;; Sex can juicy gossip, although not normally if the participants are in an + 089      ;; Sex can juicy gossip, although not normally if the participants are in an
- 085      ;; established sexual relationship. + 090      ;; established sexual relationship.
- 086      :sex {:verb :sex :keys [:actor :other :location] + 091      :sex {:verb :sex :keys [:actor :other :location]
- 087            :inferences [{:verb :sex :actor :other :other :actor}]} + 092            :inferences [{:verb :sex :actor :other :other :actor}]}
- 088      ;; Thefts are interesting + 093      ;; Thefts are interesting
- 089      :steal {:verb :steal :keys [:actor :other :object :location]} + 094      :steal {:verb :steal :keys [:actor :other :object :location]}
- 090      ;; The succession of rulers is interesting; of respected craftsmen, + 095      ;; The succession of rulers is interesting; of respected craftsmen,
- 091      ;; potentially also interesting. + 096      ;; potentially also interesting.
- 092      :succession {:verb :succession :keys [:actor :other :location :rank]} + 097      :succession {:verb :succession :keys [:actor :other :location :rank]}
- 093      ;; The start of ongoing open conflict between to characters may be interesting + 098      ;; The start of ongoing open conflict between to characters may be interesting
- 094      :war {:verb :war :keys [:actor :other :location] + 099      :war {:verb :war :keys [:actor :other :location]
- 095            :inferences [{:verb :war :actor :other :other :actor}]} + 100            :inferences [{:verb :war :actor :other :other :actor}]}
- 096      }) + 101      })
- 097   + 102  
- 098   + 103  
- 099  (defn interest-in-character + 104  (defn interest-in-character
- 100    "Integer representation of how interesting this `character` is to this + 105    "Integer representation of how interesting this `character` is to this
- 101    `gossip`. + 106    `gossip`.
- 102    *TODO:* this assumes that characters are passed as keywords, but, as + 107    *TODO:* this assumes that characters are passed as keywords, but, as
- 103    documented above, they probably have to be maps, to allow for degradation." + 108    documented above, they probably have to be maps, to allow for degradation."
- 104    [gossip character] + 109    [gossip character]
- 105    (count + 110    (count
- 106      (concat + 111      (concat
- 107        (filter #(= (:actor % character)) (:knowledge gossip)) + 112        (filter #(= (:actor % character)) (:knowledge gossip))
- 108        (filter #(= (:other % character)) (:knowledge gossip))))) + 113        (filter #(= (:other % character)) (:knowledge gossip)))))
- 109   + 114  
- 110  (defn interesting-character? + 115  (defn interesting-character?
- 111    "Boolean representation of whether this `character` is interesting to this + 116    "Boolean representation of whether this `character` is interesting to this
- 112    `gossip`." + 117    `gossip`."
- 113    [gossip character] + 118    [gossip character]
- 114    (> (interest-in-character gossip character) 0)) + 119    (> (interest-in-character gossip character) 0))
- 115   + 120  
- 116  (defn interest-in-location + 121  (defn interest-in-location
- 117    "Integer representation of how interesting this `location` is to this + 122    "Integer representation of how interesting this `location` is to this
- 118    `gossip`." + 123    `gossip`."
- 119    [gossip location] + 124    [gossip location]
- 120    (cond + 125    (cond
- 121      (and (map? location) (number? (:x location)) (number? (:y location))) + 126      (and (map? location) (number? (:x location)) (number? (:y location)))
- 122      (if-let [home (:home gossip)] + 127      (if-let [home (:home gossip)]
- 123        (let [d (distance-between location home) + 128        (let [d (distance-between location home)
- 124              i (/ 10000 d) ;; 10000 at metre scale is 10km; interest should + 129              i (/ 10000 d) ;; 10000 at metre scale is 10km; interest should
- 125              ;;fall of with distance from home, but possibly on a log scale + 130              ;;fall off with distance from home, but possibly on a log scale
- 126              ] + 131              ]
- 127          (if (> i 1) i 0)) + 132          (if (> i 1) i 0))
- 128        0) + 133        0)
- 129      (coll? location) + 134      (coll? location)
- 130      (reduce + 135      (reduce
- 131        + + 136        +
- 132        (map + 137        (map
- 133          #(interest-in-location gossip %) + 138          #(interest-in-location gossip %)
- 134          location)) + 139          location))
- 135      :else + 140      :else
- 136      (count + 141      (count
- 137        (filter + 142        (filter
- 138          #(some (fn [x] (= x location)) (:location %)) + 143          #(some (fn [x] (= x location)) (:location %))
- 139          (cons {:location (:home gossip)} (:knowledge gossip)))))) + 144          (cons {:location (:home gossip)} (:knowledge gossip))))))
- 140   + 145  
- 141  ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) -
- - 142   -
- - 143  (defn interesting-location? -
- - 144    "True if the location of this news `item` is interesting to this `gossip`." -
- - 145    [gossip item] -
- - 146    (> (interest-in-location gossip (:location item)) 0)) + 146  ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home])
147  
- - 148  (defn interesting-object? + + 148  (defn interesting-location?
- 149    [gossip object] + 149    "True if the location of this news `item` is interesting to this `gossip`."
- 150    ;; TODO: Not yet (really) implemented + 150    [gossip item]
- - 151    true) + + 151    (> (interest-in-location gossip (:location item)) 0))
152  
- - 153  (defn interesting-topic? + + 153  (defn interesting-object?
- 154    [gossip topic] + 154    [gossip object]
155    ;; TODO: Not yet (really) implemented @@ -475,272 +475,302 @@ 157  
+ + 158  (defn interesting-topic? +
+ + 159    [gossip topic] +
+ + 160    ;; TODO: Not yet (really) implemented +
+ + 161    true) +
+ + 162   +
- 158  (defn interesting-item? + 163  (defn interesting-item?
- 159    "True if anything about this news `item` is interesting to this `gossip`." + 164    "True if anything about this news `item` is interesting to this `gossip`."
- 160    [gossip item] + 165    [gossip item]
- 161       (or + 166       (or
- 162         (interesting-character? gossip (:actor item)) + 167         (interesting-character? gossip (:actor item))
- 163         (interesting-character? gossip (:other item)) + 168         (interesting-character? gossip (:other item))
- 164         (interesting-location? gossip (:location item)) + 169         (interesting-location? gossip (:location item))
- 165         (interesting-object? gossip (:object item)) + 170         (interesting-object? gossip (:object item))
- 166         (interesting-topic? gossip (:verb item)))) + 171         (interesting-topic? gossip (:verb item))))
- 167   + 172  
- 168  (defn infer + 173  (defn infer
- 169    "Infer a new knowledge item from this `item`, following this `rule`" + 174    "Infer a new knowledge item from this `item`, following this `rule`"
- 170    [item rule] + 175    [item rule]
- 171    (reduce merge + 176    (reduce merge
- 172            item + 177            item
- 173            (cons + 178            (cons
- 174              {:verb (:verb rule)} + 179              {:verb (:verb rule)}
- 175              (map (fn [k] {k (apply (k rule) (list item))}) + 180              (map (fn [k] {k (apply (k rule) (list item))})
- 176                   (remove + 181                   (remove
- 177                     #(= % :verb) + 182                     #(= % :verb)
- 178                     (keys rule)))))) + 183                     (keys rule))))))
- 179   + 184  
- 180  (declare learn-news-item) + 185  (declare learn-news-item)
- 181   + 186  
- 182  (defn make-all-inferences + 187  (defn make-all-inferences
- 183    "Return a list of knowledge entries inferred from this news `item` by this + 188    "Return a list of knowledge entries that can be inferred from this news
- 184    `gossip`." + 189    `item`."
- 185    [item] + 190    [item]
- 186    (set + 191    (set
- 187      (reduce + 192      (reduce
- 188        concat + 193        concat
- 189        (map + 194        (map
- 190          #(:knowledge (learn-news-item {} (infer item %) false)) + 195          #(:knowledge (learn-news-item {} (infer item %) false))
- 191          (:inferences (news-topics (:verb item))))))) + 196          (:inferences (news-topics (:verb item)))))))
- 192   + 197  
- 193  (defn degrade-character + 198  (defn degrade-character
- 194    "Return a character specification like this `character`, but comprising + 199    "Return a character specification like this `character`, but comprising
- 195    only those properties this `gossip` is interested in." + 200    only those properties this `gossip` is interested in."
- 196    [gossip character] + 201    [gossip character]
- 197    ;; TODO: Not yet (really) implemented + 202    ;; TODO: Not yet (really) implemented
- 198    character) + 203    character)
- 199   + 204  
- 200  (defn degrade-location + 205  (defn degrade-location
- 201    "Return a location specification like this `location`, but comprising + 206    "Return a location specification like this `location`, but comprising
- 202    only those elements this `gossip` is interested in. If none, return + 207    only those elements this `gossip` is interested in. If none, return
- 203    `nil`." + 208    `nil`."
- 204    [gossip location] + 209    [gossip location]
- 205    (let [l (if + 210    (let [l (if
- 206      (coll? location) + 211      (coll? location)
- 207      (filter + 212      (filter
- 208        #(when (interesting-location? gossip %) %) + 213        #(when (interesting-location? gossip %) %)
- 209        location))] + 214        location))]
- 210      (when-not (empty? l) l))) + 215      (when-not (empty? l) l)))
- 211   + 216  
- 212  (defn learn-news-item + 217  (defn learn-news-item
- 213    "Return a gossip like this `gossip`, which has learned this news `item` if + 218    "Return a gossip like this `gossip`, which has learned this news `item` if
- 214    it is of interest to them." + 219    it is of interest to them."
- 215    ;; TODO: Not yet implemented + 220    ;; TODO: Not yet implemented
- 216    ([gossip item] + 221    ([gossip item]
- 217     (learn-news-item gossip item true)) + 222     (learn-news-item gossip item true))
- 218    ([gossip item follow-inferences?] + 223    ([gossip item follow-inferences?]
- 219     (if + 224     (if
- 220       (interesting-item? gossip item) -
- - 221       (let [g (assoc gossip :knowledge -
- - 222                 (cons -
- - 223                   (assoc + 225       (interesting-item? gossip item)
- 224                     item + 226       (let +
+ + 227         [g (assoc +
+ + 228              gossip +
+ + 229              :knowledge
- 225                     :nth-hand (if + 230              (cons
- 226                                 (number? (:nth-hand item)) + 231                (assoc +
+ + 232                  item +
+ + 233                  :nth-hand (if +
+ + 234                              (number? (:nth-hand item))
- 227                                 (inc (:nth-hand item)) + 235                              (inc (:nth-hand item))
- 228                                 1) + 236                              1)
- - 229                     :date (if (number? (:date item)) (:date item) (game-time)) + + 237                  :time-stamp (if
- - 230                     :location (degrade-location gossip (:location item)) + + 238                                (number? (:time-stamp item))
- - 231                     ;; ought to degratde the location -
- - 232                     ;; ought to maybe-degrade characters we're not yet interested in -
- - 233                     ) -
- - 234                   ;; ought not to add knowledge items we already have, except -
- - 235                   ;; to replace if new item is of increased specificity -
- - 236                   (:knowledge gossip)))] + + 239                                (:time-stamp item)
- 237         (if follow-inferences? + 240                                (game-time))
- - 238           (assoc -
- - 239             g + + 241                  :location (degrade-location gossip (:location item))
- 240             :knowledge + 242                  ;; TODO: ought to maybe-degrade characters we're not yet interested in
- - 241             (concat (:knowledge g) (make-all-inferences item))) + + 243                  ) +
+ + 244                ;; TODO: ought not to add knowledge items we already have, except +
+ + 245                ;; to replace if new item is of increased specificity +
+ + 246                (:knowledge gossip)))] +
+ + 247         (if follow-inferences? +
+ + 248           (assoc
- 242           g)) + 249             g +
+ + 250             :knowledge +
+ + 251             (concat (:knowledge g) (make-all-inferences item))) +
+ + 252           g))
- 243       gossip))) + 253       gossip)))
- 244   + 254  
- 245   + 255  
- 246   + 256  
diff --git a/docs/cloverage/the_great_game/objects/container.clj.html b/docs/cloverage/the_great_game/objects/container.clj.html new file mode 100644 index 0000000..992deb8 --- /dev/null +++ b/docs/cloverage/the_great_game/objects/container.clj.html @@ -0,0 +1,41 @@ + + + + the_great_game/objects/container.clj + + + + 001  (ns the-great-game.objects.container +
+ + 002    (:require +
+ + 003      [the-great-game.objects.game-object :refer :all])) +
+ + 004   +
+ + 005  (defprotocol ProtoContainer +
+ + 006    (contents +
+ + 007      [container] +
+ + 008              "Return a sequence of the contents of this `container`, or `nil` if empty.") +
+ + 009    (is-empty? +
+ + 010      [container] +
+ + 011      "Return `true` if this `container` is empty, else `false`.")) +
+ + diff --git a/docs/cloverage/the_great_game/objects/game_object.clj.html b/docs/cloverage/the_great_game/objects/game_object.clj.html new file mode 100644 index 0000000..d553a53 --- /dev/null +++ b/docs/cloverage/the_great_game/objects/game_object.clj.html @@ -0,0 +1,65 @@ + + + + the_great_game/objects/game_object.clj + + + + 001  (ns the-great-game.objects.game-object +
+ + 002    "Anything at all in the game world") +
+ + 003   +
+ + 004  (defprotocol ProtoObject +
+ + 005    "An object in the world" +
+ + 006    (id [object] "Returns the unique id of this object.") +
+ + 007    (reify-object +
+ + 008      [object] +
+ + 009      "Adds this `object` to the global object list. If the `object` has a +
+ + 010      non-nil value for its `id` method, keys it to that id - **but** if the +
+ + 011      id value is already in use, throws a hard exception. Returns the id to +
+ + 012      which the object is keyed in the global object list.")) +
+ + 013   +
+ + 014  (defrecord GameObject +
+ + 015    [id] +
+ + 016    ;; "An object in the world" +
+ + 017    ProtoObject +
+ + 018    (id [_] id) +
+ + 019    (reify-object [object] "TODO: doesn't work yet")) +
+ + diff --git a/docs/codox/Baking-the-world.html b/docs/codox/Baking-the-world.html index c588bd8..0e624ad 100644 --- a/docs/codox/Baking-the-world.html +++ b/docs/codox/Baking-the-world.html @@ -1,6 +1,6 @@ -Baking the world

Baking the world

+Baking the world

Baking the world

Wednesday, 8 May 2019

Devogilla’s Bridge in Dumfries, early foourteenth century

In previous posts, I’ve described algorithms for dynamically populating and dynamically settling a game world. But at kilometre scale (and I think we need a higher resolution than that - something closer to hectare scale), settling the British Isles using my existing algorithms takes about 24 hours of continuous compute on an eight core, 3GHz machine. You cannot do that every time you launch a new game.

diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html new file mode 100644 index 0000000..966e6e7 --- /dev/null +++ b/docs/codox/Pathmaking.html @@ -0,0 +1,79 @@ + +Pathmaking

Pathmaking

+

NOTE: this file is called ‘pathmaking’, not ‘pathfinding’, because ‘pathfinding’ has a very specific meaning/usage in game design which is only part of what I want to talk about here.

+

Stages in creating routes between locations

+

The ‘procedural’ phase

+

see also Baking-the-world

+

Towards the end of the procedural phase of the build process, every agent within the game world must move through the complete range of their needs-driven repertoire. Merchants must traverse their trading routes; soldiers must patrol routes within their employers domain; primary producers and craftspeople must visit the craftspeople who supply them; every character must visit their local inn, and must move daily between their dwelling and their workplace if different; and so on. They must do this over a considerable period - say 365 simulated days.

+

At the start of the baking phase, routes - roads, tracks and paths - designed by the game designers already exist.

+

The algorithmic part of choosing a route is the same during this baking phase as in actual game play except that during the baking phase the routemap is being dynamically updated, creating a new path or augmenting an existing path wherever any agent goes.

+

Thus the ‘weight’ of any section of route is a function of the total number of times that route segment has been traversed by an agent during this baking phase. At the end of the baking phase, routes travelled more than R times are rendered as roads, T times as tracks, and P times as footpaths, where R, T and P are all chosen by the game designer but generally R > T > P.

+

Algorithmic rules

+
    +
  1. No route may pass through any part of a reserved holding, except the holding which is its origin, if any, and the holding which is its destination (and in any case we won’t render paths or roads within holdings, although traversal information may be used to determine whether a holding, or part of it, is paved/cobbled;
  2. +
  3. No route may pass through any building, with the exception of a city gate;
  4. +
  5. We don’t have bicycles: going uphill costs work, and you don’t get that cost back on the down hill. Indeed, downhills are at least as expensive to traverse as flat ground;
  6. +
  7. Any existing route segment costs only a third as much to traverse as open ground having the same gradient;
  8. +
  9. A more used route costs less to traverse than a less used route.
  10. +
+

River crossings

+

Crossing rivers is expensive - say five times as expensive as level open ground (but this will probably need tuning). Where a river is shallow enough, (i.e. where the amount of water passing is below some threshold) then a path crossing will be rendered as stepping stones and a track crossing as a ford. Where it’s deeper than that, a path crossing either isn’t rendered at all or is rendered as a light footbridge. A track or road crossing is rendered as a bridge. However, the maximum length of a bridge varies with the amount of traffic on the route segment, and if the crossing exceeds that length then a ferry is used. Road bridges will be more substantial than track bridges, for example in a biome with both timber and stone available road bridges might be rendered as stone bridges while track bridges were rendered as timber. If the watercourse is marked as navigable, the bridge must have a lifting section. It is assumed here that bridges are genetic buildings like most other in-game buildings, and so don’t need to be individually designed.

+

Representation

+

At some stage in the future I’ll have actual game models to work with and $DEITY knows what the representation of those will be like, but to get this started I need two inputs: a heightmap, from which gradients can be derived, and a route map. The heightmap can conventionally be a monochrome raster image, and that’s easy. The route map needs to be a vector representation, and SVG will be as convenient as any. So from the point of view of routing during the baking phase, a route map shall be an SVG with the following classes:

+
    +
  • exclusion used on polygons representing e.g. buildings, or impassable terrain which may not be traversed at all;
  • +
  • openwater used on polygons representing oceans and lakes, which may be traversed only by boat (or possibly swimming, for limited distances);
  • +
  • watercourse used on paths representing rivers or streams, with some additional attribute giving rate of flow;
  • +
  • navigable may be an additional class on a path also marked watercourse indicating that it is navigable by cargo vessels;
  • +
  • route used on paths representing a path, track or road whose final representation will be dynamically assigned at the end of baking, with some additional attribute giving total traversals to date;
  • +
  • path used on paths representing a path designed by the designers, which will certainly be rendered as a path no matter how frequently it is traversed;
  • +
  • track used on paths representing a track designed by the designers, which will certainly be rendered as a track no matter how frequently it is traversed;
  • +
  • road used on paths representing a road designed by the designers, which will certainly be rendered as a road no matter how (in)frequently it is traversed.
  • +
+

At the end of the baking process the routing engine should be able to write out an updated SVG. New routes should be splined curves, so that they have natural bends not sharp angles.

+

The ‘Walkmap’

+

Conventional game pathfinding practice is to divide the traversable area into a mesh of ‘convex polygons’, where a ‘convex polygon’ in this sense is, essentially, a polygon having no bays. Routes traverse from a starting point to the centre of a polygon ajacent to the polygon in which the starting point is located. I have reservations as to whether this will do what I need since I’m not convinced it will produce naturalistic paths; however, it’s worth at least experimenting with.

+

There are existing utilities (such as hmm) which convert heightmaps into suitable geometry files; however all I’ve found so far convert to [binary STL](https://en.wikipedia.org/wiki/STL_(file_format)). This isn’t a format I find very useful; I’d prefer an XML dialect, and SVG is good enough for me.

+

hmm converts the heightmap into a tesselation of triangles, which are necessarily convex in the sense given above. Utilities (such as binary-stl-toASCII) exist to convert binary STL to an ASCII encoded equivalent, which may be easier to parse.

+

So the pipeline seems to be

+
    +
  1. heightmap to binary STL
  2. +
  3. (optional) binary STL to ASCII STL
  4. +
  5. STL to SVG (where ‘SVG’ here is shorthand for a convenient vector format)
  6. +
  7. Exclude holdings, buildings, open water, and other exclusions
  8. +
  9. Where we have excluded exclusions, ensure that any non-convex polygons we’ve created are divided into new convex polygons.
  10. +
+

I shall have to write custom code for 4 and 5 above, and, looking at what’s available, probably 3 as well.

+

I’m working on a separate library, walkmap, which will attempt to implement this pipeline.

+

Pathmaking and scale

+

Dealing with large heightmaps - doing anything at all with them - is extremely compute intensive. Just converting a 1000x1000 heightmap from STL to SVG is currently taking 8 hours and 15 minutes; and it ends up with a 46 megabyte SVG file! However, most of the time cost is in writing. Reading the STL file takes four and a quarter seconds; converting that STL to SVG in memory takes less than five seconds. So the huge cost is writing the file with Dali.

+
walkmap.core=> (time (def stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl")))
+"Elapsed time: 4285.231513 msecs"
+#'walkmap.core/stl
+walkmap.core=> (time (def svg (stl-to-svg stl)))
+"Elapsed time: 4865.798059 msecs"
+#'walkmap.core/svg
+
+

“Elapsed time: 2.969569560662E7 msecs”

+

We cannot effectively do routing at metre scale - which is what we ultimately need in settlements - across the entire thousand kilometre square map in one pass. But also we don’t need to because much of the continent is by design relatively unpeopled and relatively untracked. The basic concept of the Steppe is that there are two north/south routes, the one over the Midnight Pass into the Great Place and the one via Hans’hua down to the Cities of the Coast, and those can be part of the ‘designed roads’ map. So we can basically exclude most of the Steppe from routing altogether. We can also - for equally obvious reasons exclude the ocean. The ocean makes up roughly half of the 1000x1000 kilometre map, the steppe and plateau take up half of what’s left, mountain massifs eat into the remainder and my feeling is that much of the eastern part of the continent is probably too arid to be settled. So we probably end up only having to dynamically route about 20% of the entire map.

+

However, this doesn’t get round the main problem with scale, and pathmaking. If we pathmake at kilometre scale, then curves will be necessarily very long and sweeping - because each path segment will be at least a kilometre long. And, actually, that’s fine for very long distance roads in unpopulated fairly flat territory. It’s not so good for long distance roads in rugged terrain, but…

+

Phase one: hand-designed routes

+

While, given the bottlenecks of the few mountain passes and the one possible pass over the plateau, the caravan routes we want would almost certainly emerge organically out of dynamic routing. But, actually, I know more or less where they need to be and it’s probably easiest to hand design them. It will certainly save an enormous amount of brute-force compute time.

+

I think I have to accept that if I want Alpe d’Huez-style switchbacks up the Sunset and Midnight passes, they’re going to have to be hand designed. The same applies to where the Hans’hua caravan road ascends the plateau.

+

Phase two: route segments ‘for free’ out of settlement activity

+

If we start by pathmaking around settlements, we can make a first start by giving the template for a holding a segment of track parallel to and just in front of its frontage, and a segment of path along its left hand and rear edges. That, actually, is going to provide 90% of all routing within a settlement, and it’s done for us within the Settling-a-game-world phase.

+

Phase three: metre scale routing around settlements

+

So if we then collect groups of contiguous 100x100 metre zones each of which has at least one settled holding, we can route at one metre scale over that and what it will essentially do is join up and augment the route segments generated by settlement. Areas of dense settlement do not make up a great deal of the map. Note that experience may show that the metre scale routing is superflous.

+

Phases four, five and six: increasing granularity

+

Taking the augmented route map comprised of

+
    +
  1. The hand-designed, mainly long distance or plot-important routes;
  2. +
  3. The route segments bordering holdings;
  4. +
  5. The metre scale routing
  6. +
+

we can then collect contiguous groups of zones each having at least one holding, where in phase four each zone is a kilometre square and divided into 100x100 grid so that we route at ten metre scale; in phase five we use ten kilometre by ten kilometre zones and we route at 100 metre scale; in phase six, 100 km by 100 km zones and we route at kilometre scale. This process should automatically link up all settlements on the south and west coasts, all those on the north coast, and all in the Great Place; and seeing that the posited pre-designed caravan roads already join the south coast to the north, the north to the Great Place and the Great Place to the south coast, we’re done.

+

At least one of phases three, four, five and six is probably redundant; but without trying I’m not sure which.

+

Tidying up

+

After the full set of increasing-scale passes is complete, we should automatically cull any route segments generated in the settlement phase which have never actually been traversed.

+

Following that, there may be scope for some final manual tweaking, if desired; I think this is most likely to happen where roads routed at kilometre scale cross rugged terrain.

\ No newline at end of file diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index 8a50174..5ea5c9e 100644 --- a/docs/codox/Populating-a-game-world.html +++ b/docs/codox/Populating-a-game-world.html @@ -1,6 +1,6 @@ -Populating a game world

Populating a game world

+Populating a game world

Populating a game world

Saturday, 6 July 2013

(You might want to read this essay in conjunction with my older essay, Settling a game world, which covers similar ground but which this hopefully advances on)

For an economy to work people have to be able to move between occupations to fill economic niches. In steady state, non player character (NPC) males become adult as ‘vagrants’, and then move through the state transitions described in this document. The pattern for females is different.

diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index f7b58df..1bdac1f 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,6 +1,6 @@ -Settling a game world

Settling a game world

+Settling a game world

Settling a game world

Wednesday, 30 December 2009

This essay is part of a series with ‘Worlds and Flats’ and ‘The spread of knowledge in a large game world’; if you haven’t read those you may want to read them before reading this. This essay describes how a large world can come into being and can evolve. I’ve written again on this subject since - see ‘Populating a game world’)

Microworld

diff --git a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html index 9dd26f5..21193ca 100644 --- a/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html +++ b/docs/codox/The-spread-of-knowledge-in-a-large-game-world.html @@ -1,6 +1,6 @@ -The spread of knowledge in a large game world

The spread of knowledge in a large game world

+The spread of knowledge in a large game world

The spread of knowledge in a large game world

Saturday, 26 April 2008

part of the role of Dandelion, in The Witcher games, is to provide the player with news

Note

diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 7e5c1ad..44121b1 100644 --- a/docs/codox/Voice-acting-considered-harmful.html +++ b/docs/codox/Voice-acting-considered-harmful.html @@ -1,6 +1,6 @@ -Voice acting considered harmful

Voice acting considered harmful

+Voice acting considered harmful

Voice acting considered harmful

Wednesday, 25 February 2015

The Witcher: Conversation with Kalkstein

Long, long, time ago, I can still remember when… we played (and wrote) adventure games where the user typed at a command line, and the system printed back at them. A Read-Eval-Print loop in the classic Lisp sense, and I wrote my adventure games in Lisp. I used the same opportunistic parser whether the developer was building the game Create a new room north of here called dungeon-3 the player was playing the game Pick up the rusty sword and go north or the player was talking to a non-player character Say to the wizard ‘can you tell me the way to the castle’ Of course, the parser didn’t ‘understand’ English. It worked on trees of words, in which terminal nodes were actions and branching nodes were key words, and it had the property that any word it didn’t recognise at that point in sentence was a noise word and could be ignored. A few special hacks (such as ‘the’, ‘a’, or ‘an’ was an indicator that what came next was probably a noun phrase, and thus that if there was more than one sword in the player’s immediate environment the one that was wanted was the one tagged with the adjective ‘rusty’), and you ended up with a parser that most of the time convincingly interpreted most of what the player threw at it.

diff --git a/docs/codox/economy.html b/docs/codox/economy.html index b5c7ecb..c4dbafb 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,6 +1,6 @@ -Game world economy

Game world economy

+Game world economy

Game world economy

Broadly this essay extends ideas presented in Populating a game world, q.v.

Primary producers

Herdsfolk

diff --git a/docs/codox/index.html b/docs/codox/index.html index d645463..f7aab85 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.1-SNAPSHOT

The-great-game 0.1.1-SNAPSHOT

Released under the GNU General Public License,version 2.0 or (at your option) any later version

Prototype code towards the great game I've been writing about for ten years, and know I will never finish.

Installation

To install, add the following dependency to your project or build file:

[the-great-game "0.1.1-SNAPSHOT"]

Topics

Namespaces

the-great-game.agent.agent

Anything in the game world with agency

Public variables and functions:

    the-great-game.gossip.gossip

    Interchange of news events between gossip agents

    Public variables and functions:

    the-great-game.merchants.markets

    Adjusting quantities and prices in markets.

    Public variables and functions:

    the-great-game.merchants.merchant-utils

    Useful functions for doing low-level things with merchants.

    the-great-game.merchants.merchants

    Trade planning for merchants, primarily.

    Public variables and functions:

    the-great-game.merchants.planning

    Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

    the-great-game.merchants.strategies.simple

    Default trading strategy for merchants.

    Public variables and functions:

    the-great-game.utils

    TODO: write docs

    Public variables and functions:

    the-great-game.world.location

    Functions dealing with location in the world.

    Public variables and functions:

    the-great-game.world.routes

    Conceptual (plan level) routes, represented as tuples of location ids.

    Public variables and functions:

    the-great-game.world.run

    Run the whole simulation

    Public variables and functions:

    the-great-game.world.world

    Access to data about the world

    Public variables and functions:

    \ No newline at end of file +The-great-game 0.1.1-SNAPSHOT

    The-great-game 0.1.1-SNAPSHOT

    Released under the GNU General Public License,version 2.0 or (at your option) any later version

    Prototype code towards the great game I've been writing about for ten years, and know I will never finish.

    Installation

    To install, add the following dependency to your project or build file:

    [the-great-game "0.1.1-SNAPSHOT"]

    Topics

    Namespaces

    the-great-game.agent.agent

    Anything in the game world with agency

    Public variables and functions:

    the-great-game.gossip.gossip

    Interchange of news events between gossip agents

    Public variables and functions:

    the-great-game.merchants.markets

    Adjusting quantities and prices in markets.

    Public variables and functions:

    the-great-game.merchants.merchant-utils

    Useful functions for doing low-level things with merchants.

    the-great-game.merchants.merchants

    Trade planning for merchants, primarily.

    Public variables and functions:

    the-great-game.merchants.planning

    Trade planning for merchants, primarily. This follows a simple-minded generate-and-test strategy and currently generates plans for all possible routes from the current location. This may not scale. Also, routes do not currently have cost or risk associated with them.

    the-great-game.merchants.strategies.simple

    Default trading strategy for merchants.

    Public variables and functions:

    the-great-game.objects.container

    TODO: write docs

    Public variables and functions:

    the-great-game.objects.game-object

    Anything at all in the game world

    Public variables and functions:

    the-great-game.utils

    TODO: write docs

    Public variables and functions:

    the-great-game.world.location

    Functions dealing with location in the world.

    Public variables and functions:

    the-great-game.world.routes

    Conceptual (plan level) routes, represented as tuples of location ids.

    Public variables and functions:

    the-great-game.world.run

    Run the whole simulation

    Public variables and functions:

    the-great-game.world.world

    Access to data about the world

    Public variables and functions:

    \ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html index ebeff11..a892c58 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,6 +1,6 @@ -Introduction to the-great-game

    Introduction to the-great-game

    +Introduction to the-great-game

    Introduction to the-great-game

    The Great Game

    In this essay I’m going to try to pull together a number of my architectural ideas about the Great Game which I know I’m never actually going to build - because it’s vastly too big for any one person to build - into one overall vision.

    So, firstly, how does one characterise this game?

    diff --git a/docs/codox/modelling_trading_cost_and_risk.html b/docs/codox/modelling_trading_cost_and_risk.html index 58c4b74..93ea97f 100644 --- a/docs/codox/modelling_trading_cost_and_risk.html +++ b/docs/codox/modelling_trading_cost_and_risk.html @@ -1,6 +1,6 @@ -Modelling trading cost and risk

    Modelling trading cost and risk

    +Modelling trading cost and risk

    Modelling trading cost and risk

    In a dynamic pre-firearms world with many small states and contested regions, trade is not going to be straightforward. Not only will different routes have different physical characteristics - more or less mountainous, more or fewer unbridged river crossings - they will also have different political characteristics: more of less taxed, more or less effectively policed.

    Raids by outlaws are expected to be part of the game economy. News of raids are the sort of things which may propagate through the gossip system. So are changes in taxation regime. Obviously, knowledge items can affect merchants’ trading strategy; in existing prototype code, individual merchants already each keep their own cache of known historical prices, and exchange historical price data with one another; and use this price data to select trades to make.

    So: to what extent is it worth modelling the spread of knowledge of trade cost and risk?

    diff --git a/docs/codox/naming-of-characters.html b/docs/codox/naming-of-characters.html index 3258a8a..e0f2dea 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters

    Naming of Characters

    +Naming of Characters

    Naming of Characters

    Generally speaking, in modern RPGs, every character with any impact on the plot has a distinct name. But if we are going to give all non-player characters sufficient agency to impact on the plot, then we must have a way of naming tens or hundreds of thousands of characters, and distinct names will become problematic (even if we’re procedurally generating names, which we shall have to do. So this note is about how characters are named.

    The full name of each character will be made up as follows:

    [epithet] [clan] [personal-name] the [trade-or-rank] of [location], son/daughter of [parent]

    diff --git a/docs/codox/on-dying.html b/docs/codox/on-dying.html index d84d7de..a52e81a 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,6 +1,6 @@ -On Dying

    On Dying

    +On Dying

    On Dying

    Death is the end of your story. One of the tropes in games which, for me, most breaks immersion is when you lose a fight and are presented with a screen that says ‘you are dead. Do you want to reload your last save?’ Life is not like that. We do not have save-states. We die.

    So how could this be better handled?

    You lose a fight. Switch to cutscene: the battlefield, after the fight, your body is there. Probably no sound. A party of non-enemies crosses the battlefield and finds your body. We see surprise and concern. They gather around you. Cut to interior scene, you are in a bed, unconcious, being tended; cut to similar interior scene, you are in a bed, conscious, being tended; cut to exterior scene, you are sitting with some of your saviours, and the game restarts.

    diff --git a/docs/codox/orgnic-quests.html b/docs/codox/orgnic-quests.html index 05c712d..49b6973 100644 --- a/docs/codox/orgnic-quests.html +++ b/docs/codox/orgnic-quests.html @@ -1,6 +1,6 @@ -Organic Quests

    Organic Quests

    +Organic Quests

    Organic Quests

    The structure of a modern Role Playing Came revolves around ‘quests’: tasks that the player character is invited to do, either by the framing narrative of the game or by some non-player character (‘the Quest Giver’). Normally there is one core quest which provides the overarching narrative for the whole game. [Wikipedia](https://en.wikipedia.org/wiki/Quest_(gaming)) offers a typology of quests as follows:

    1. Kill quests
    2. diff --git a/docs/codox/sandbox.html b/docs/codox/sandbox.html index e5b4a25..975e6d8 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,6 +1,6 @@ -Sandbox

      Sandbox

      +Sandbox

      Sandbox

      Up to now I’ve been thinking of the Great Game as essentially an RPG with some sandbox-like elements; but I think it may be better to think of it as a sandbox game with some RPG like elements.

      Why?

      The core of the game is a world in which non-player characters have enough individual knowledge of the world and their immediate surroundings that they can sensibly answer questions like

      diff --git a/docs/codox/sexual-dimorphism.html b/docs/codox/sexual-dimorphism.html index de010b7..90c7153 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism

      Sexual dimorphism

      +Sexual dimorphism

      Sexual dimorphism

      This essay is going to upset a lot of people, so let’s start with a statement of what it is about: it is an attempt to describe the systematically different behaviours of men and women, in sufficient detail that this can be represented by agents in a game world. It’s trying to allow as broad as possible a range of cultures to be represented, so when I’m talking about what I consider to be behaviours of particular cultures, I’ll say that.

      Of course, I’m writing this from the view point of an old white male. It’s not possible to write about these things from a totally neutral viewpoint, and every one of us will have prejudices.

      OK? Let’s start.

      diff --git a/docs/codox/the-great-game.agent.agent.html b/docs/codox/the-great-game.agent.agent.html index 079a700..7e659af 100644 --- a/docs/codox/the-great-game.agent.agent.html +++ b/docs/codox/the-great-game.agent.agent.html @@ -1,3 +1,10 @@ -the-great-game.agent.agent documentation

      the-great-game.agent.agent

      Anything in the game world with agency

      \ No newline at end of file +the-great-game.agent.agent documentation

      the-great-game.agent.agent

      Anything in the game world with agency

      ProtoAgent

      protocol

      An object which can act in the world

      members

      act

      (act actor world circle)

      Allow actor to do something in this world, in the context of this circle; return the new state of the actor if something was done, nil if nothing was done. Circle is expected to be one of

      +
        +
      • :active - actors within visual/audible range of the player character;
      • +
      • :pending - actors not in the active circle, but sufficiently close to it that they may enter the active circle within a short period;
      • +
      • :background - actors who are active in the background in order to handle trade, news, et cetera;
      • +
      • other - actors who are not members of any other circle, although I’m not clear whether it would ever be appropriate to invoke an act method on them.
      • +
      +

      The act method must not have side effects; it must only return a new state. If the actor’s intention is to seek to change the state of something else in the game world, it must add a representation of that intention to the sequence which will be returned by its pending-intentions method.

      pending-intentions

      (pending-intentions actor)

      Returns a sequence of effects an actor intends, as a consequence of acting. The encoding of these is not yet defined.

      \ No newline at end of file diff --git a/docs/codox/the-great-game.gossip.gossip.html b/docs/codox/the-great-game.gossip.gossip.html index 177c964..3e5f1a4 100644 --- a/docs/codox/the-great-game.gossip.gossip.html +++ b/docs/codox/the-great-game.gossip.gossip.html @@ -1,3 +1,3 @@ -the-great-game.gossip.gossip documentation

      the-great-game.gossip.gossip

      Interchange of news events between gossip agents

      dialogue

      (dialogue enquirer respondent world)

      Dialogue between an enquirer and an agent in this world; returns a map identical to enquirer except that its :gossip collection may have additional entries.

      gather-news

      (gather-news world)(gather-news world gossip)

      TODO: write docs

      move-gossip

      (move-gossip gossip world new-location)

      Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

      run

      (run world)

      Return a world like this world, with news items exchanged between gossip agents.

      \ No newline at end of file +the-great-game.gossip.gossip documentation

      the-great-game.gossip.gossip

      Interchange of news events between gossip agents

      dialogue

      (dialogue enquirer respondent world)

      Dialogue between an enquirer and an agent in this world; returns a map identical to enquirer except that its :gossip collection may have additional entries.

      gather-news

      (gather-news world)(gather-news world gossip)

      TODO: write docs

      move-gossip

      (move-gossip gossip world new-location)

      Return a world like this world but with this gossip moved to this new-location. Many gossips are essentially shadow-records of agents of other types, and the movement of the gossip should be controlled by the run function of the type of the record they shadow. The #run function below does NOT call this function.

      run

      (run world)

      Return a world like this world, with news items exchanged between gossip agents.

      \ No newline at end of file diff --git a/docs/codox/the-great-game.gossip.news-items.html b/docs/codox/the-great-game.gossip.news-items.html index ee90317..f3c6832 100644 --- a/docs/codox/the-great-game.gossip.news-items.html +++ b/docs/codox/the-great-game.gossip.news-items.html @@ -1,6 +1,6 @@ -the-great-game.gossip.news-items documentation

      the-great-game.gossip.news-items

      Categories of news events interesting to gossip agents

      degrade-character

      (degrade-character gossip character)

      Return a character specification like this character, but comprising only those properties this gossip is interested in.

      degrade-location

      (degrade-location gossip location)

      Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

      infer

      (infer item rule)

      Infer a new knowledge item from this item, following this rule

      interest-in-character

      (interest-in-character gossip character)

      Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

      interest-in-location

      (interest-in-location gossip location)

      Integer representation of how interesting this location is to this gossip.

      interesting-character?

      (interesting-character? gossip character)

      Boolean representation of whether this character is interesting to this gossip.

      interesting-item?

      (interesting-item? gossip item)

      True if anything about this news item is interesting to this gossip.

      interesting-location?

      (interesting-location? gossip item)

      True if the location of this news item is interesting to this gossip.

      interesting-object?

      (interesting-object? gossip object)

      TODO: write docs

      interesting-topic?

      (interesting-topic? gossip topic)

      TODO: write docs

      learn-news-item

      (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

      Return a gossip like this gossip, which has learned this news item if it is of interest to them.

      make-all-inferences

      (make-all-inferences item)

      Return a list of knowledge entries inferred from this news item by this gossip.

      news-topics

      Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:

      +the-great-game.gossip.news-items documentation

      the-great-game.gossip.news-items

      Categories of news events interesting to gossip agents

      degrade-character

      (degrade-character gossip character)

      Return a character specification like this character, but comprising only those properties this gossip is interested in.

      degrade-location

      (degrade-location gossip location)

      Return a location specification like this location, but comprising only those elements this gossip is interested in. If none, return nil.

      infer

      (infer item rule)

      Infer a new knowledge item from this item, following this rule

      interest-in-character

      (interest-in-character gossip character)

      Integer representation of how interesting this character is to this gossip. TODO: this assumes that characters are passed as keywords, but, as documented above, they probably have to be maps, to allow for degradation.

      interest-in-location

      (interest-in-location gossip location)

      Integer representation of how interesting this location is to this gossip.

      interesting-character?

      (interesting-character? gossip character)

      Boolean representation of whether this character is interesting to this gossip.

      interesting-item?

      (interesting-item? gossip item)

      True if anything about this news item is interesting to this gossip.

      interesting-location?

      (interesting-location? gossip item)

      True if the location of this news item is interesting to this gossip.

      interesting-object?

      (interesting-object? gossip object)

      TODO: write docs

      interesting-topic?

      (interesting-topic? gossip topic)

      TODO: write docs

      learn-news-item

      (learn-news-item gossip item)(learn-news-item gossip item follow-inferences?)

      Return a gossip like this gossip, which has learned this news item if it is of interest to them.

      make-all-inferences

      (make-all-inferences item)

      Return a list of knowledge entries that can be inferred from this news item.

      news-topics

      Topics of interest to gossip agents. Topics are keyed in this map by their verbs. The keys associated with each topic are the extra pieces of information required to give context to a gossip item. Generally: