Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2fd09a9b73
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -3,7 +3,9 @@ pom.xml.asc
|
|||
*.jar
|
||||
*.class
|
||||
*.log
|
||||
*.stl
|
||||
[0-9a-f]*-init.clj
|
||||
/bin/
|
||||
/lib/
|
||||
/classes/
|
||||
/target/
|
||||
|
@ -18,4 +20,9 @@ pom.xml.asc
|
|||
.cpcache/
|
||||
*~
|
||||
|
||||
doc/.~lock.Population.ods#
|
||||
|
||||
.settings/
|
||||
|
||||
.classpath
|
||||
|
||||
.project
|
||||
|
|
114
doc/Pathmaking.md
Normal file
114
doc/Pathmaking.md
Normal file
|
@ -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.
|
|
@ -127,6 +127,32 @@
|
|||
<td class="with-number">4.03 %</td>
|
||||
<td class="with-number">173</td><td class="with-number">6</td><td class="with-number">124</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="the_great_game/objects/container.clj.html">the-great-game.objects.container</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 2 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 2 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">11</td><td class="with-number">1</td><td class="with-number">2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="the_great_game/objects/game_object.clj.html">the-great-game.objects.game-object</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:60.0%;
|
||||
float:left;"> 3 </div><div class="not-covered"
|
||||
style="width:40.0%;
|
||||
float:left;"> 2 </div></td>
|
||||
<td class="with-number">60.00 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:60.0%;
|
||||
float:left;"> 3 </div><div class="not-covered"
|
||||
style="width:40.0%;
|
||||
float:left;"> 2 </div></td>
|
||||
<td class="with-number">60.00 %</td>
|
||||
<td class="with-number">19</td><td class="with-number">2</td><td class="with-number">5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="the_great_game/time.clj.html">the-great-game.time</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:99.5850622406639%;
|
||||
|
|
|
@ -8,22 +8,130 @@
|
|||
001 (ns the-great-game.agent.agent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Anything in the game world with agency")
|
||||
002 "Anything in the game world with agency"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 (:require [the-great-game.objects.game-object :refer [ProtoObject]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 [the-great-game.objects.container :refer [ProtoContainer]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
003
|
||||
005
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 ;; hierarchy of needs probably gets implemented here
|
||||
006 ;; hierarchy of needs probably gets implemented here
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
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
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
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.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
007
|
||||
009
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
010 (defprotocol ProtoAgent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 "An object which can act in the world"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 (act
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 [actor world circle]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 "Allow `actor` to do something in this `world`, in the context of this
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 `circle`; return the new state of the actor if something was done, `nil`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 if nothing was done. Circle is expected to be one of
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
017
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 * `:active` - actors within visual/audible range of the player
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 character;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 * `:pending` - actors not in the active circle, but sufficiently close
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 to it that they may enter the active circle within a short period;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 * `:background` - actors who are active in the background in order to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 handle trade, news, et cetera;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 * `other` - actors who are not members of any other circle, although
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 I'm not clear whether it would ever be appropriate to invoke an
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 `act` method on them.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
027
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 The `act` method *must not* have side effects; it must *only* return a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 new state. If the actor's intention is to seek to change the state of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 something else in the game world, it must add a representation of that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 intention to the sequence which will be returned by its
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 `pending-intentions` method.")
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 (pending-intentions
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 [actor]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 "Returns a sequence of effects an actor intends, as a consequence of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 acting. The encoding of these is not yet defined."))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
037
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;; (defrecord Agent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ;; "A default agent."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ;; ProtoObject
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 ;; ProtoContainer
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 ;; ProtoAgent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ;; )
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
41
docs/cloverage/the_great_game/objects/container.clj.html
Normal file
41
docs/cloverage/the_great_game/objects/container.clj.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../../coverage.css"/> <title> the_great_game/objects/container.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns the-great-game.objects.container
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 (:require
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 [the-great-game.objects.game-object :refer :all]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
004
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
005 (defprotocol ProtoContainer
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 (contents
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [container]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 "Return a sequence of the contents of this `container`, or `nil` if empty.")
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 (is-empty?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 [container]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 "Return `true` if this `container` is empty, else `false`."))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
65
docs/cloverage/the_great_game/objects/game_object.clj.html
Normal file
65
docs/cloverage/the_great_game/objects/game_object.clj.html
Normal file
|
@ -0,0 +1,65 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../../coverage.css"/> <title> the_great_game/objects/game_object.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns the-great-game.objects.game-object
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Anything at all in the game world")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
003
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
004 (defprotocol ProtoObject
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 "An object in the world"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 (id [object] "Returns the unique id of this object.")
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 (reify-object
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [object]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 "Adds this `object` to the global object list. If the `object` has a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 non-nil value for its `id` method, keys it to that id - **but** if the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 id value is already in use, throws a hard exception. Returns the id to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 which the object is keyed in the global object list."))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
013
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
014 (defrecord GameObject
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 [id]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;; "An object in the world"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ProtoObject
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
018 (id [_] id)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
019 (reify-object [object] "TODO: doesn't work yet"))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
79
docs/codox/Pathmaking.html
Normal file
79
docs/codox/Pathmaking.html
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
docs/codox/the-great-game.objects.container.html
Normal file
3
docs/codox/the-great-game.objects.container.html
Normal file
File diff suppressed because one or more lines are too long
3
docs/codox/the-great-game.objects.game-object.html
Normal file
3
docs/codox/the-great-game.objects.game-object.html
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,43 @@
|
|||
(ns the-great-game.agent.agent
|
||||
"Anything in the game world with agency")
|
||||
"Anything in the game world with agency"
|
||||
(:require [the-great-game.objects.game-object :refer [ProtoObject]]
|
||||
[the-great-game.objects.container :refer [ProtoContainer]]))
|
||||
|
||||
;; hierarchy of needs probably gets implemented here
|
||||
;; I'm probably going to want to defprotocol stuff, to define the hierarchy
|
||||
;; of things in the gameworld; either that or drop to Java, wich I'd rather not do.
|
||||
|
||||
(defprotocol ProtoAgent
|
||||
"An object which can act in the world"
|
||||
(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
|
||||
[actor]
|
||||
"Returns a sequence of effects an actor intends, as a consequence of
|
||||
acting. The encoding of these is not yet defined."))
|
||||
|
||||
;; (defrecord Agent
|
||||
;; "A default agent."
|
||||
;; ProtoObject
|
||||
;; ProtoContainer
|
||||
;; ProtoAgent
|
||||
;; )
|
||||
|
|
11
src/the_great_game/objects/container.clj
Normal file
11
src/the_great_game/objects/container.clj
Normal file
|
@ -0,0 +1,11 @@
|
|||
(ns the-great-game.objects.container
|
||||
(:require
|
||||
[the-great-game.objects.game-object :refer :all]))
|
||||
|
||||
(defprotocol ProtoContainer
|
||||
(contents
|
||||
[container]
|
||||
"Return a sequence of the contents of this `container`, or `nil` if empty.")
|
||||
(is-empty?
|
||||
[container]
|
||||
"Return `true` if this `container` is empty, else `false`."))
|
19
src/the_great_game/objects/game_object.clj
Normal file
19
src/the_great_game/objects/game_object.clj
Normal file
|
@ -0,0 +1,19 @@
|
|||
(ns the-great-game.objects.game-object
|
||||
"Anything at all in the game world")
|
||||
|
||||
(defprotocol ProtoObject
|
||||
"An object in the world"
|
||||
(id [object] "Returns the unique id of this object.")
|
||||
(reify-object
|
||||
[object]
|
||||
"Adds this `object` to the global object list. If the `object` has a
|
||||
non-nil value for its `id` method, keys it to that id - **but** if the
|
||||
id value is already in use, throws a hard exception. Returns the id to
|
||||
which the object is keyed in the global object list."))
|
||||
|
||||
(defrecord GameObject
|
||||
[id]
|
||||
;; "An object in the world"
|
||||
ProtoObject
|
||||
(id [_] id)
|
||||
(reify-object [object] "TODO: doesn't work yet"))
|
Loading…
Reference in a new issue