Baking the world
+Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Baking the world
Wednesday, 8 May 2019
-Devorgilla’s Bridge in Dumfries, early foourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.
+Devorgilla’s Bridge in Dumfries, early fourteenth century. This clearly shows how a genetic buildings approach to bridges can be made to work: a single element is repeated to span the necessary distance. That element can be stretched vertically and laterally to match the location, and can be rendered in different stone finishes to match local geology.
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.
So the game development has to run in four phases: the first three phases happen during development, to create a satisfactory, already populated and settled, initial world for the game to start from. This is particularly necessary if hand-crafted buildings and environments are going to be added to the world; the designers of those buildings and environments have to be able to see the context into which their models must fit.
Phase one: proving - the procedural world
diff --git a/docs/codox/Canonical-dictionary.html b/docs/codox/Canonical-dictionary.html new file mode 100644 index 0000000..b1b2312 --- /dev/null +++ b/docs/codox/Canonical-dictionary.html @@ -0,0 +1,35 @@ + +Generated by Codox
The-great-game 0.1.2-SNAPSHOT
A Canonical dictionary for this documentation
+Where a word is used in the documentation for The Great Game and its related projects, this file describes the canonical meaning of that word. This is because a lot of the concepts in play are messy and ambiguous, so that at times even I am confused by what I mean. The presence of this file is an acknowledment of this difficulty, and an implicit admission that not all the documentation is, at this stage anyway, consistent.
+Actor
+An actor
is a thing which performs actions within the game world. Thus a tree is (almost certainly) not an actor, and things like sheep and rabbits that run about are probably not actors, but an animal which may pro-actively interact with the player character (such as a predator, or a beast of burden, or even a prey species which may flee) is an actor. In god mode, if implemented, the player can inhabit any actor within the game world.
Agent
+Agent
is probably just a synonym for actor
. If it is different in any way, that way has not yet been determined.
Gossip
+A gossip
is an actor
who exchanges news with other actors
, even when the player character is not nearby. Thus gossips
are the mechanism by which news propagates through the game world, and also the mechanism by which information degrades. Broadly:
-
+
innkeepers
(and possibly some others) aregossips
who do not move; rather, they gather information from gossips who do move, and allnon-player characters
local to the are deemed to know everything that their localinnkeeper
knows;
+ merchants
(and possibly some others) aregossips
who do move from place to place, and thus transfer news.
+
See the spread of knowledge in a large game world.
+Heightmap
+A heightmap
is a raster image of the world, such that the intensity in which an area is coloured represents the value of some variable, by default height, of that area.
Holding
+A holding
is a polygon ‘owned’ by an actor
on which are built appropriate building units representing the actors
craft and status.
Location
+A location
value is a sequence comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting, they won’t be passed on. So location information will degrade progressively as the item is passed along.
It is assumed that the :home
of a character is a location in this sense.
Examples
+-
+
- [{:x 5445678 :y 9684351}] +
- [{:x 5445678 :y 9684351} :karalin-palace :hanshua] +
Merchant
+A merchant
is an actor
and gossip
who trades goods, and incidentally conveys news, between markets
.
Non-player character
+A non-player character
is, for our purposes, an actor
capable of engaging in conversation with the player character
. Note, however, that, from a software point of view, the player character
is just a special case of a non-player character
.
Player character
+The player character
is the unique actor
within the game currently controlled and inhabited by the player.
Route
+A route
is a pre-prepared path through the game world that an actor
may take. Most actors
are not constrained to follow routes
, but in general routes
have lower traversal cost than other terrain.
Generated by Codox
The-great-game 0.1.2-SNAPSHOT
On the consequences of a dynamic game environment for storytelling
+First, a framing disclaimer: in Racundra’s First Cruise, Arthur Ransome describes coming across a half built - and by the time he saw it, already obsolete - wooden sailing ship, in a Baltic forest. An old man was building it, by himself. He had been building it since he had been a young man. It’s clear that Ransome believed the ship would never be finished. It’s not clear whether the old man believed that it would, but nevertheless he was building it.
+I will never build a complete version of The Great Game; it will probably never even be a playable prototype. It is a minor side-project of someone who
+-
+
- Is ill, and consequently has inconsistent levels of energy and concentration; +
- Has other things to do in the real world which necessarily take precedence. +
Nevertheless, in making design choices I want to specify something which could be built, which could, except for the technical innovations I’m trying myself to build, be built with the existing state of the art, and which if built, would be engaging and interesting to play.
+The defining characteristic of Role Playing Games - the subcategory of games in which I am interested - is that the actions, decisions and choices of the player make a significant difference to the outcome of the plot, significantly affect change in the world. This already raises challenges for the cinematic elements in telling the game story, and those cinematic elements are one of the key rewards to the player, one of the elements of the game’s presentation which most build, and hold, player engagement. These challenges are clearly expressed in two very good videos I’ve watched recently: Who’s Commanding Shepard in Mass Effect?, which discusses how much control the player actually has/should have over the decisions of the character they play as; and What Happened with Mass Effect Andromeda’s Animation?, which discusses how the more control the player has, the bigger the task of authoring animation of all conversations and plot events becomes.
+There are two key innovations I want to make in The Great Game which set it apart from existing Role Playing Games, both of which make the production of engaging cinematic presentation of conversation more difficult, nd I’ll handle each in turn. But before I do, there’s something I need to make clear about the nature of video games themselves: what they are for. Video games are a vehicle to tell stories, to convey narrative. They’re a rich vehicle, because the narrative is not fixed: it is at least to some degree mutable, responsive to the input of the audience: the player.
+Clear? Let’s move on.
+The innovations I am interested in are
+Unconstrained natural speech input/output
+I want the player to be able to interact with non-player characters (and, indeed, potentially with other player characters, in a multi-player context) simply by speaking to them. This means that the things the player character says cannot be scripted: there is no way for the game designer to predict the full repertoire of the player’s input. It also means that the game must construct, and put into the mouth of the non-player character being addressed, an appropriate response, given
+-
+
- The speech interpretation engine’s interpretation of what it is the player said; +
- The immediate game and plot context; +
- The particular non-player character addressed’s knowledge of the game world; +
- The particular non-player character’s attitude towards the player; +
- The particular non-player character’s speech idiosyncracies, dialect, and voice +
and it must be pretty clear that the full range of potential responses is extremely large. Consequently, it’s impossible that all non-player character speech acts can be voice acted; rather, this sort of generated speech must be synthesised. But a consequence of this is that the non-player character’s facial animation during the conversation also cannot be motion captured from a human actor; rather, it, too, must be synthesized.
+This doesn’t mean that speech acts by non-player characters which make plot points or advance the narrative can’t be voice acted, but it does mean that the voice acting must be consistent with the simulated voice used for that non-player character - which is to say, probably, that the non-player character must use a synthetic voice derived from the voice of that particular voice actor.
+Dynamic game environment
+Modern Role Playing Games are, in effect, extremely complex state machines: if you do the same things in the same sequence, the same outcomes will always occur. In a world full of monsters, bandits, warring armies and other dangers, the same quest givers will be in the same places at the same times. They are clockwork worlds, filled with clockwork automata. Of course, this has the advantage that is makes testing easier - and in a game with a complex branching narrative and many quests, testing is inevitably hard.
+My vision for The Great Game is different. It is that the economy - and with it, the day to day choices of non-player characters - should be modelled. This means, non-player characters may unexpectedly die. Of course, you could implement a tag for plot-relevant characters which prevents them being killed (except when required by the plot).
+Plot follows player
+As Role Playing Games have moved towards open worlds - where the player’s movement in the environment is relatively unconstrained - the clockwork has become strained. The player has to get to particular locations where particular events happen, and so the player has to be very heavily signposted. Another solution - which I’d like to explore - is ‘plot follows character’. The player is free to wander at will in the world, and plot relevant events will happen on their path. And by that I don’t mean that we associate a set of non-player characters which each quest - as current Role Playing Games do - and then uproot the whole set from wherever they normally live in the world and dumping down in the player’s path; but rather, for each role in a quest or plot event, we define a set of characteristics required to fulfill that role, and then, when the player comes to a place where there are a set of characters who have those characteristics, the quest or plot event will happen.
+Cut scenes, cinematics and rewarding the player
+There’s no doubt at all that ‘cut scenes’ - in effect, short movies spliced into game play during which the player has no decisions to make but can simply watch the scene unroll - are elements of modern games which players enjoy, and see to some extent as ‘rewards’. And in many games, these are beautifully constructed works. It is a very widely held view that the quality of cutscenes depends to a large degree on human authorship. The three choices I’ve made above:
+-
+
- We can’t always know exactly what non-player characters will say (although perhaps we can in the context of cut scenes where the player has no input); +
- We can’t always know exactly which non-player characters will speak the lines; +
- We can’t predict what a non-player character will say in response to a question, or how long that will take; +
- We can’t always know where any particular plot event will take place. +
Each of these, obviously, make the task of authoring an animation harder. The general summary of what I’m saying here is that, although in animating a conversation or cutscene what the animator is essentially animating is the skeletons of the characters, and, provided that all character models are rigged on essentially similar skeletons, substituting one character model for another in an animated scene isn’t a huge issue, with so much unknowable it is impossible that hand-authoring will be practicable, and so a lot will depend on the quality of the conversation system not merely to to produce convincingly enunciated and emoted sound, but also appropriate character animation and attractive cinematography. As you will have learned from the Mass Effect analysis videos I linked to above, that’s a big ask.
+Essentially the gamble here is that players will find the much richer conversations, and consequent emergent gameplay, possible with non-player charcaters who have dynamic knowledge about their world sufficiently engaging to compensate for a less compelling cinematic experience. I believe that they would; but really the only way to find out would be to try.
+Interestingly, an early preview of CD PRoject Red’s not-yet-complete Cyberpunk 2077 suggests that there will be very, very few cutscenes, suggesting that these very experienced storytellers don’t feel they need cutscenes either to tell their story or maintain player engagement. (Later) It has to be said other commentators who have also played the Cyberpunk 2077 preview say that there are a lot of cutscenes, one of them describing the prologue as ‘about half cutscenes’ - so this impression I formed may be wrong).
Generated by Codox
The-great-game 0.1.1
Game Play
+Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Game Play
The principles of game play which I’m looking for are a reaction against all I see as wrong in modern video games. So let’s set out what these are:
-
diff --git a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html
index 33918d7..30a2724 100644
--- a/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html
+++ b/docs/codox/Gossip_scripted_plot_and_Johnny_Silverhand.html
@@ -1,7 +1,7 @@
-
Gossip, scripted plot, and Johnny Silverhand Generated by Codox
The-great-game 0.1.1
Gossip, scripted plot, and Johnny Silverhand
-I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,
+Gossip, scripted plot, and Johnny Silverhand Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Gossip, scripted plot, and Johnny Silverhand
+I’ve been writing literally for years – since Voice acting considered harmful in 2015 – about game worlds in which the player speaks to non-player characters just by speaking the words they choose in their normal voice, and the non-player character replies using a pipeline that goes, essentially,
- Alexa/Siri style speech interpretation;
- A decision on whether to co-operate based on the particular NPC’s general demeanor and particular attitude to the player; diff --git a/docs/codox/Organic_Quests.html b/docs/codox/Organic_Quests.html index 055e53e..d2e0969 100644 --- a/docs/codox/Organic_Quests.html +++ b/docs/codox/Organic_Quests.html @@ -1,6 +1,6 @@ -
- Kill quests @@ -12,14 +12,14 @@
- Hybrids
- The location of the quest giver at the beginning of the quest;
- The location from which the quest object must be collected;
- The location to which the quest object must be delivered;
- The location of the quest giver at the end of the quest.
- Procedural (genetic) buildings; +
- Procedural settlement planning; +
- Procedural characters, probably based on MakeHuman ‘Mass Produce’ plugin, using walk animation based on TestWalkingChar; +
- Characters with their own hierarchy of needs, and their own means of planning to fulfil these; +
- Characters with individualised knowledge about the world; +
- Characters who can parse typed questions, and produce either a textual or audio response; +
- Characters with procedurally generated accents (very stretch goal)! +
- Characters who can listen to spoken questions, and produce audio responses. +
: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 anact
method on them.
+- Ground floor modules, having external doors; +
- Craft modules – workshops – which will normally be ground floor (except weavers) and may have the constraint that no upper floor module can cover them; +
- Upper floor modules, having NO external doors (but linking internal doors); +
- Roof modules +
:primary
a ground floor main entrance module
+ :secondary
a module which can be upper or ground floor
+ :upper
a module which can only be on an upper floor, for example one with a projecting gallery, balcony or overhang.
+:left
an exit in the centre of the left wall
+ :left-front
an exit in the centre of the left half of the front wall
+ :front
an exit in the centre of the front wall
+ :right-front
an exit in the centre of the right half of the front wall
+ :right
an exit in the centre of the right wall
+ :right-back
an exit in the centre of the right half of the back wall
+ :left-back
an exit in the centre of the back wall
+- Bare masonry - constrained to upland or plateau terrain, and to coastal culture +
- Painted masonry - constrained to upland or plateau terrain, and to coastal culture +
- Half-timbered - not available on plateau terrain +
- Weatherboarded - constrained to forest terrain +
- Brick - constrained to arable or arid terrain +
- To establish the broad principle of genetic buildings, by creating a function which reproducibly creates reproducible buildings at specified locations, such that different buildings are credibly varied but a building at a specified location is always (modulo economic change) the same. +
- Create good rectangular buildings, and investigate whether a single function can be used to create buildings of more than one family (e.g. can it produce flat roofed, north African style, mud brick houses as well as pitch roofed, half timbered northern European houses?) +
- Establish whether, in my current state of fairly severe mental illness, I can actually produce any usable code at all. +
- terrain types to which it is appropriate; +
- crafts to which it is appropriate; +
- cultures to which it is appropriate. +
date
- the date on which the reported event happened;
+ nth-hand
- the number of agents the news item has passed through;
+ verb
- what it is that happened (key intonews-topics
);
+actor
is the id of the character who it is reported performed the action;
+ other
is the id of the character on whom it is reported the action was performed;
+ location
is the place at which the action was performed;
+ object
is an object (or possibly list of objects?) relevant to the action;
+ price
is special to buy/sell, but of significant interest to merchants.
+- :merchant - the id of the
merchant
for whom the plan was created;
+ - :origin - the city from which the trade starts; +
- :destination - the city to which the trade is planned; +
- :commodity - the
commodity
to be carried;
+ - :buy-price - the price at which that
commodity
can be bought;
+ - :expected-price - the price at which the
merchant
anticipates thatcommodity
can be sold;
+ - :distance - the number of stages in the planned journey +
- :dist-to-home - the distance from
destination
to themerchant
’s home city.
+ - :merchant - the id of the
merchant
for whom the plan was created;
+ - :origin - the city from which the trade starts; +
- :destination - the city to which the trade is planned; +
- :commodity - the
commodity
to be carried;
+ - :buy-price - the price at which that
commodity
can be bought;
+ - :expected-price - the price at which the
merchant
anticipates thatcommodity
can be sold;
+ - :distance - the number of stages in the planned journey +
- :dist-to-home - the distance from
destination
to themerchant
’s home city.
+ - Baking the world
- Pathmaking
- Populating a game world
- Settling a game world
- The spread of knowledge in a large game world
- Voice acting considered harmful
- Game world economy
- Introduction to the-great-game
- Modelling trading cost and risk
- Naming of Characters
- On Dying
- Organic Quests
- Sandbox
- Sexual dimorphism
- Baking the world
- A Canonical dictionary for this documentation
- On the consequences of a dynamic game environment for storytelling
- Game Play
- Gossip, scripted plot, and Johnny Silverhand
- Organic Quests
- Pathmaking
- Populating a game world
- Roadmap
- Settling a game world
- Simulation layers
- The spread of knowledge in a large game world
- The Uncanny Valley, and dynamically generated dialogue
- Voice acting considered harmful
- Building on Microworld
- Game world economy
- Introduction to the-great-game
- Modelling trading cost and risk
- Naming of Characters
- On Dying
- Sandbox
- Sexual dimorphism
Organic Quests Generated by Codox
The-great-game 0.1.1
\ No newline at end of file diff --git a/docs/codox/Pathmaking.html b/docs/codox/Pathmaking.html index 17d6c51..3ad8777 100644 --- a/docs/codox/Pathmaking.html +++ b/docs/codox/Pathmaking.html @@ -1,6 +1,6 @@ -Organic Quests
+Organic Quests Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file +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:
‘Gather quests’ are more frequently referred to in the literature as ‘fetch quests’, and ‘kill quests’ are simply a specialised form of fetch quest where the item to be fetched is a trophy of the kill. And the trophy could be just the knowledge that the kill has happened. A delivery quest is a sort of reverse fetch quest: instead of going to some location or NPC and getting a specific item to return to the quest giver, the player is tasked to take a specific item from the quest giver to some location or NPC.
-Note, however, that if we consider a delivery quest to have four locations, where some of these locations may be conincident, then a delivery quest and a fetch quest become the same thing. Thus
+Note, however, that if we consider a delivery quest to have four locations, where some of these locations may be coincident, then a delivery quest and a fetch quest become the same thing. Thus
This characterisation assumes that at the end of each quest, the player must rendezvous with the quest giver at the end of the quest, either to report completion or to collect a reward. Obviously, there could be some quests where this fourth location is not required, because there is no need to report back (for example, if the quest giver was dying/has died) and no reward to be collected.
+This characterisation assumes that at the end of each quest, the player must rendezvous with the quest giver, either to report completion or to collect a reward. Obviously, there could be some quests where this fourth location is not required, because there is no need to report back (for example, if the quest giver was dying/has died) and no reward to be collected.
Note that a location is not necessarily a fixed x/y location on the map; in a kill quest, for example, location 2 is the current location of the target, and moves when the target moves; location 3 and 4 are both normally the current location of the quest giver, and move when the quest giver moves.
Hybrids are in effect chains of quests: do this task in order to get this precondition of this other task, in order to get the overall objective; obviously such chains can be deep and involved - the ‘main quest’ of every role playing game I know of is a chain or hybrid quest.
My understanding is that what Wikipedia means by a ‘syntax quest’ is what one would normally call a puzzle.
@@ -34,12 +34,13 @@which are combined together into more or less complex chains, where the simplest chain is a single quest.
Given that quests are as simple as this, it’s obvious that narrative sophistication is required to make them interesting; and this point is clearly made by some variants of roguelike games which procedurally generate quests: they’re generally pretty dull. By contrast, the Witcher series is full of fetch-quests which are made to really matter by being wrapped in interesting character interaction and narrative plausibility. Very often this takes the form of tragedy: as one reviewer pointed out, the missing relatives that Geralt is asked to find generally turn out to be (horribly) dead. In other words, creative scripting tends to deliver much more narratively satisfying quests than is usually delivered by procedural generation.
But, if we’re thinking of a game with much more intelligent non-player characters with much more conversational repertoir, as I am, can satisfying quests emerge organically? In space trading games such as Elite, a primary activity is moving goods from markets with surplus (and thus low prices) to markets with shortage (and thus high prices). This is, in effect, a game made up of deliver quests - but rather than deliver quests which are scripted, they are deliver quests which arise organically out of the structure of the game world.
-I already have working code for non-player character merchants, who move goods from city to city based on market information available to them. For player characters to join in this trading is an organic activity emerging from the structure of the world, which provides an activity. But moving merchants provides a market opportunity for bandits, who can intercept and steal cargoes, and so for mercenaries, who can protect cargoes from bandits, and so on. And because I have an architecture that allows non-player characters to fill economic niches, there will be non-player characters in all these niches.
+I already have working code for non-player character merchants, who move goods from city to city based on market information available to them. For player characters to join in this trading is an organic activity emerging from the structure of the world. But moving merchants provides a market opportunity for bandits, who can intercept and steal cargoes, and so for mercenaries, who can protect cargoes from bandits, and so on. And because I have an architecture that allows non-player characters to change occupation to fill economic niches, there will be non-player characters in all these niches.
Where a non-player character can act, so can a player character: when a (non-player character) merchant seeks to hire a caravan guard and a player character responds, that’s an organic escort quest.
-The key idea behind organic quests is that the circumstance and requirments for quests emerges as an emergent behaviour out of the mechanics of the game world. A non-player character doesn’t know that there is a player character who is different from them; rather, when a non-player character needs something they can’t readily achieve for themselves, they will ask other characters to help, and that may include the player character.
+The key idea behind organic quests is that the circumstance and requirements for quests emerge as an emergent behaviour out of the mechanics of the game world. A non-player character doesn’t know that there is a player character who is different from them; rather, when a non-player character needs something they can’t readily achieve for themselves, they will ask other characters to help, and that may include the player character.
This means, of course, that characters need a goal-seeking planning algorithm to decide their actions, with one option in any plan being ‘ask for help’. Thus, ‘asking for help’ becomes a mechanism within the game, a normal behaviour. Ideally non-player characters will keep track of quite complex webs of loyalty and of obligation - debts of honour, duties of hospitality, collective loyalties. So that, if you do a favour for some character in the world, that character’s tribe, friends, obligation circle, whatever, are now more likely to do favours for you.
Obviously, this doesn’t stop you doing jobs you get directly paid/rewarded for, but I’d like the web of obligation to be at least potentially much richer than just tit for tat.
Related to this notion is the notion that, if you are asked to do a task by a character and you do it well, whether for pay or as a favour, your reputation for being competent in tasks of that kind will improve and the more likely it is that other characters will ask you to do similar tasks; and this will apply to virtually anything another character can ask of you in the game world, from carrying out an assassination to delivering a message to finding a quantiy of some specific commodity to having sex.
So quests can emerge organically from the mechanics of the world and be richly varied; I’m confident that will work. What I’m not confident of is that they can be narratively satisfying. This relates directly to the generation of speech.
Stuff to consider
-The games Middle Earth: Shadow of Mordor, and Middle Earth: Shadow of War have a procedural story system called Nemesis, which is worth a look.
The games Middle Earth: Shadow of Mordor, and Middle Earth: Shadow of War have a procedural story system called Nemesis, which is worth a look.
+There’s an interesting critique of Red Dead Redemption 2 which is relevant to what I’m saying here.
Pathmaking Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Pathmaking
+Pathmaking Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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
see also Baking the world
diff --git a/docs/codox/Populating-a-game-world.html b/docs/codox/Populating-a-game-world.html index c02a951..f529c56 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 Generated by Codox
The-great-game 0.1.1
Populating a game world
+Populating a game world Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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/Roadmap.html b/docs/codox/Roadmap.html new file mode 100644 index 0000000..79a4459 --- /dev/null +++ b/docs/codox/Roadmap.html @@ -0,0 +1,22 @@ + +Roadmap Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/Settling-a-game-world.html b/docs/codox/Settling-a-game-world.html index cbf569e..fa2eeed 100644 --- a/docs/codox/Settling-a-game-world.html +++ b/docs/codox/Settling-a-game-world.html @@ -1,6 +1,6 @@ -Roadmap
+This document outlines a plan to move forward from where I am in June 2021.
+JMonkeyEngine
+JMonkeyEngine is not, at this time, an AAA game engine. But at the same time I’m never, really, going to build an AAA game. It is a working game engine which can display characters on screen in scenery and have them move around, and, actually, they can be fairly sophisticated. It will be resaonably easy to integrate Clojure code with JMonkeyEngine - easier than it would be to integrate either Clojure or Common Lisp with Unreal Engine or Unity 3D. As a significant added bonus, JMonkeyEngine is open source.
+Consequently I plan to stop agonising about what game engine to use, and seriously focus on getting something working in JMonkeyEngine.
+Not Reinventing Wheels
+JMonkeyEngine already has working code for walking animated characters, which is entirely adequate to proof-of-concept what I want to do. Rather than try to implement them myself, I just intend to use existing JMonkeyEngine code as far as possible.
+The 1Km World
+I propose to build a 1Km square world, containing one settlement, as a proof of concept for
+-
+
At that stage, I have a technology demonstrator that will be interesting. It still leaves the big procedural world builder still to do, but it would be enough technology to get other people interested in the project.
Settling a game world Generated by Codox
The-great-game 0.1.1
Settling a game world
+Settling a game world Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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/Simulation-layers.html b/docs/codox/Simulation-layers.html index 0e37f3a..dac2565 100644 --- a/docs/codox/Simulation-layers.html +++ b/docs/codox/Simulation-layers.html @@ -1,6 +1,6 @@ -Simulation layers Generated by Codox
The-great-game 0.1.1
Simulation layers
+Simulation layers Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Simulation layers
In essence, the environment for The Great Game is broadly descended from games like the original Elite space trading game, and Sid Meier’s Pirates!, with some elements from political simulations like for example SimCity.
That is to say there is
An economy simulation
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 eb95181..d6084f2 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 Generated by Codox
The-great-game 0.1.1
The spread of knowledge in a large game world
+The spread of knowledge in a large game world Generated by Codox
The-great-game 0.1.2-SNAPSHOT
The spread of knowledge in a large game world
Saturday, 26 April 2008
Note
diff --git a/docs/codox/Uncanny_dialogue.html b/docs/codox/Uncanny_dialogue.html index e3e619e..6793ccc 100644 --- a/docs/codox/Uncanny_dialogue.html +++ b/docs/codox/Uncanny_dialogue.html @@ -1,6 +1,6 @@ -The Uncanny Valley, and dynamically generated dialogue Generated by Codox
The-great-game 0.1.1
The Uncanny Valley, and dynamically generated dialogue
+The Uncanny Valley, and dynamically generated dialogue Generated by Codox
The-great-game 0.1.2-SNAPSHOT
The Uncanny Valley, and dynamically generated dialogue
If the player is allowed to just speak arbitrary dialogue, then the conversation animation of the player character cannot be designed. If non-player characters are able to engage dynamically generated dialogue, in response to events in the game which are not scripted, then their conversation animation for those dialogues cannot be designed. So conversation animation must almost always be dynamically generated, largely from an augmented text of the speech act. With non-player characters, emotional content of a speech act can be generated by exactly the same process which generates the text. Extracting emotional content information from the player character’s voice may be more challenging.
It would be possible to avoid animating the player character’s face by using a first-person camera. However, I don’t personally find this makes for a very engaging game experience.
These thoughts were prompted by a very interesting video and Twitter thread about the perceived failings in the character animation system of Mass Effect Andromeda.
diff --git a/docs/codox/Voice-acting-considered-harmful.html b/docs/codox/Voice-acting-considered-harmful.html index 17e9dec..e47d8c2 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 Generated by Codox
The-great-game 0.1.1
Voice acting considered harmful
+Voice acting considered harmful Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Voice acting considered harmful
Wednesday, 25 February 2015
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/building_on_microworld.html b/docs/codox/building_on_microworld.html new file mode 100644 index 0000000..60744ec --- /dev/null +++ b/docs/codox/building_on_microworld.html @@ -0,0 +1,7 @@ + +Building on Microworld Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.agent.agent.html b/docs/codox/cc.journeyman.the-great-game.agent.agent.html new file mode 100644 index 0000000..95e3177 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.agent.agent.html @@ -0,0 +1,10 @@ + +Building on Microworld
+In Settling a Game World I intended that a world should be populated by setting agents - settlers - to explore the map and select places to settle according to particular rules. In the meantime, I’ve built MicroWorld, a rule driven cellular automaton which makes a reasonably good job of modelling human settlement. It works, and I now plan to use it, as detailed in this note; but there are issues.
+First and foremost, it’s slow, and both processor and memory hungry. That means that at continent scale, a cell of one kilometre square is the minimum size which is really possible, which isn’t small enough to create a settlement map of the density that a game will need. Even with 1 km cells, even on the most powerful machines I have access to, a continent-size map will take many days to run.
+Of course it would be possible to do a run at one km scale top identify areas which would support settlement, and then to do a run on a ten metre grid on each of those areas to more precisely plot settlement. That’s an idea which I haven’t yet explored, which might prove fruitful.
+Secondly, being a cellular automaton, MicroWorld works on a grid. This means that everything is grid aligned, which is absolutely not what I want! So I think the way to leverage this is to use MicroWorld to establish which kilometre square cells om the grid should be populated (and roughly with what), and then switch to ad hoc code to populate those cells.
cc.journeyman.the-great-game.agent.agent documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.module.html b/docs/codox/cc.journeyman.the-great-game.buildings.module.html new file mode 100644 index 0000000..c2eb88c --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.buildings.module.html @@ -0,0 +1,39 @@ + +cc.journeyman.the-great-game.agent.agent
Anything in the game world with agency; primarily but not exclusively characters.
ProtoAgent
protocol
An object which can act in the world
members
act
(act actor world circle)
Allow
+actor
to do something in thisworld
, in the context of thiscircle
; return the new state of the actor if something was done,nil
if nothing was done. Circle is expected to be one of-
+
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 itspending-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.
cc.journeyman.the-great-game.buildings.module documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html new file mode 100644 index 0000000..19bbb30 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.buildings.rectangular.html @@ -0,0 +1,32 @@ + +cc.journeyman.the-great-game.buildings.module
A module of a building; essentially something like a portacabin, which can be assembled together with other modules to make a complete building.
+Modules need to include
+-
+
Role must be one of:
+-
+
Other values for
+role
will emerge.Exits must be a sequence of keywords taken from the following list:
+-
+
A module placed on an upper floor must have no exit which opens beyond the footprint of the floor below - no doors into mid air! However, it is allowable (and indeed is necessary) to allow doors into roof spaces if the adjacent module on the same floor does not yet exist, since otherwise it would be impossible to access a new room which might later be built there.
+Load must be a small integer indicating both the weight of the module and the total amount of weight it can support. So for example a stone-built module might have a
+load
value of 4, a brick built one of 3, and a half-timbered one of 2, and a tent of 0. This means a stone ground floor module could support one further floor of stone or brick, or two further floors of half timbered construction; while a brick built ground floor could support a single brick or half-timbered upper floor but not a stone one, and a half-timbered ground floor could only support a half timbered upper floor.There also needs to be an undercroft or platform module, such that the area of the top of the platform is identical with the footprint of the building, and the altitude of the top of the platform is equal to the altitude of the terrain at the heighest corner of the building; so that the actual building doesn’t float in the air, and also so that none of the doors or windows are partly underground.
+Each module needs to wrap an actual 3d model created in Blender or whatever, and have a list of optional textures with which that model can be rendered. So an upper floor bedroom module might have the following renders:
+-
+
of course these are only examples, and also, it’s entirely possible to have for example multiple different weatherboard renders for the same module. There needs to be a way of rendering what can be built above what: for example, you can’t have a masonry clad module over a half timbered one, but you can have a half-timbered one over a masonry one.
cc.journeyman.the-great-game.buildings.rectangular documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html new file mode 100644 index 0000000..f39ba17 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.gossip.gossip.html @@ -0,0 +1,5 @@ + +cc.journeyman.the-great-game.buildings.rectangular
Build buildings with a generally rectangular floow plan.
+Motivations
+Right, the idea behind this namespace is many fold.
+-
+
Key factors in the creation of a building
+Holding
+Every building is on a holding, and, indeed, what I mean by ‘building’ here may well turn out to be ’the collection of all the permanent structures on a holding. A holding is a polygonal area of the map which does not intersect with any other holding, but for the time being we’ll make the simplifying assumption that every holding is a rectangular strip, and that ‘urban’ holdings are of a reasonably standard width (see Viking-period York) and length. Rural holdings (farms, ?wood lots) may be much larger.
+Terrain
+A building is made of the stuff of the place. In a forest, buildings will tend to be wooden; in a terrain with rocky outcrops – normally found on steep slopes – stone. On the flat lands where there’s river mud, of brick, cob, or wattle and daub. So to build a building we need to know the terrain. Terrain can be inferred from location but in practice this will be computationally expensive, so we’ll pass terrain in as an argument to the build function.
+For the time being we’ll pass it in simply as a keyword from a defined set of keywords; later it may be a more sophisticated data structure.
+Culture
+People of different cultures build distinctively different buildings, even when using the same materials. So, in our world, a Japanese wooden house looks quite different from an Anglo Saxon stave house which looks quite different from a Canadian log cabin, even though the materials are much the same and the tools available to build with are not much different.
+Culture can affect not just the overall shape of a building but also its finish and surface detail. For example, in many places in England, stone buildings are typically left bare; in rural Scotland, typically painted white or in pastel shades; in Ireland, often quite vivid colours.
+People may also show religious or cultural symbols on their buildings.
+For all these reasons, we need to know the culture of the occupant when creating a building. Again, this will initially be passed in as a keyword.
+Craft
+People in the game world have a craft, and some crafts will require different features in the building. In the broadly late-bronze-age-to medieval period within which the game is set, residence and workplace are for most people pretty much the same.
+So a baker needs an oven, a smith a forge, and so on. All crafts who do some degree retail trade will want a shop front as part of the ground floor of their dwelling. Merchants and bankers will probably have houses that are a bit more showy than others.
+Whether the ‘genetic buildings’ idea will ever really produce suitable buildings for aristons I don’t know; it seems more likely that significant strongholds (of which there will be relatively few) should all be hand modelled rather than procedurally generated.
*building-families*
dynamic
Families of buildings.
+Each family has
+-
+
Each generated building will be of one family, and will comprise modules taken only from that family.
*crafts*
dynamic
Crafts which affect building types in the game. See
Populating a game world
. TODO: placeholder*terrain-types*
dynamic
Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed.
build!
(build! holding terrain culture craft size)
Builds a building, and returns a data structure which represents it. In building the building, it adds a model of the building to the representation of the world, so it does have a side effect.
building-family
(building-family terrain culture craft gene)
A building family is essentially a collection of models of building modules which can be assembled to create buildings of a particular structural and architectural style.
cc.journeyman.the-great-game.gossip.gossip documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html new file mode 100644 index 0000000..9d3f18a --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.gossip.news-items.html @@ -0,0 +1,32 @@ + +cc.journeyman.the-great-game.gossip.gossip
Interchange of news events between gossip agents.
+Note that habitual travellers are all gossip agents; specifically, at this stage, that means merchants. When merchants are moved we also need to update the location of the gossip with the same key.
+Innkeepers are also gossip agents but do not typically move.
dialogue
(dialogue enquirer respondent world)
Dialogue between an
enquirer
and anagent
in thisworld
; returns a map identical toenquirer
except that its:gossip
collection may have additional entries.move-gossip
(move-gossip gossip world new-location)
Return a world like this
world
but with thisgossip
moved to thisnew-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.cc.journeyman.the-great-game.gossip.news-items documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.holdings.holding.html b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html new file mode 100644 index 0000000..275d0cc --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.holdings.holding.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.gossip.news-items
Categories of news events interesting to gossip agents.
+The ideas here are based on the essay The spread of knowledge in a large game world, q.v.; they’ve advanced a little beyond that and will doubtless advance further in the course of writing and debugging this namespace.
+A news item is a map with the keys:
+-
+
plus other keys taken from the
+keys
value associated with the verb innews-topics
.Notes:
+TODO
This namespace at present considers the:knowledge
of a gossip to be a flat list of propositions, each of which must be checked every time any new proposition is offered. This is woefully inefficient.compatible-item?
(compatible-item? new-item known-item)
True if
+new-item
is identical with, or less specific than,known-item
.If we already know ‘Bad Joe killed Sweet Daisy’, there’s no point in learning that ‘someone killed Sweet Daisy’, but there is point in learning ‘someone killed Sweet Daisy with poison’.
compatible-value?
(compatible-value? new-value known-value)
True if
+known-value
is the same asnew-value
, or, for each key present innew-value
, has the same value for that key.The rationale here is that if
new-value
contains new or different information, it’s worth learning; otherwise, not.degrade-character
(degrade-character gossip character)
Return a character specification like this
character
, but comprising only those properties thisgossip
is interested in.degrade-location
(degrade-location gossip location)
Return a location specification like this
location
, but comprising only those elements thisgossip
is interested in. If none, returnnil
.inc-or-one
(inc-or-one val)
If this
val
is a number, return that number incremented by one; otherwise, return 1. TODO: should probably be inutils
.interest-in-character
(interest-in-character gossip character)
Integer representation of how interesting this
character
is to thisgossip
. 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 thisgossip
.interesting-character?
(interesting-character? gossip character)
Boolean representation of whether this
character
is interesting to thisgossip
.interesting-item?
(interesting-item? gossip item)
True if anything about this news
item
is interesting to thisgossip
.interesting-location?
(interesting-location? gossip item)
True if the location of this news
item
is interesting to thisgossip
.known-item?
(known-item? gossip item)
True if this news
+item
is already known to thisgossip
.This means that the
gossip
already knows an item which identifiably has the same or more specific values for all the keys of thisitem
except:nth-hand
,:confidence
and:learned-from
.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 newsitem
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
. Thekeys
associated with each topic are the extra pieces of information required to give context to a gossip item. Generally:-
+
Notes
+Characters
+TODO but note that at most all the receiver can learn about a character from a news item is what the giver knows about that character, degraded by what the receiver finds interesting about them. If we just pass the id here, then either the receiver knows everything in the database about the character, or else the receiver knows nothing at all about the character. Neither is desirable. Further thought needed.
+By implication, the character values passed should include all the information the giver knows about the character; that can then be degraded as the receiver stores only that segment which the receiver finds interesting.
+Locations
+A ‘location’ value is a list comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain the location. If the x/y is not local to the home of the receiving agent, they won’t remember it and won’t pass it on; if any of the ids are not interesting So location information will degrade progressively as the item is passed along.
+It is assumed that the
+:home
of a character is a location in this sense.Inferences
+If an agent learns that Adam has married Betty, they can infer that Betty has married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. I’m not convinced that my representation of inferences here is ideal.
cc.journeyman.the-great-game.holdings.holding documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.location.location.html b/docs/codox/cc.journeyman.the-great-game.location.location.html new file mode 100644 index 0000000..d0eadb4 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.location.location.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.holdings.holding
TODO: write docs
ProtoHolding
protocol
members
building-origin
(building-origin holding)
Returns an oriented location - normally the right hand end of the frontage, for an urban holding - from which buildings on the holding should be built.
frontage
(frontage holding)
Returns a sequence of two locations representing the edge of the polygon which defines this holding which is considered to be the front.
cc.journeyman.the-great-game.location.location documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.markets.html b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html new file mode 100644 index 0000000..a931ec3 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.markets.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.location.location
TODO: write docs
ProtoLocation
protocol
members
altitude
(altitude location)
Return the absolute altitude of this location, which may be different from the terrain height at this location, if, for example, the location is underground or on an upper floor.
easting
(easting location)
Return the easting of this location
northing
(northing location)
Return the northing of this location
settlement
(settlement location)
Return the settlement record of the settlement in this world within whose parish polygon this location exists, or if none whose centre (inn location) is closest to this location
terrain-altitude
(terrain-altitude location)
Return the ‘ground level’ (altitude of the terrain) at this location given this world. TODO: possibly terrain-altitude should be a method of the world.
cc.journeyman.the-great-game.merchants.markets documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html new file mode 100644 index 0000000..fb7adc1 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchant-utils.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.merchants.markets
Adjusting quantities and prices in markets.
adjust-quantity-and-price
(adjust-quantity-and-price world city commodity)
Adjust the quantity of this
commodity
currently in stock in thiscity
of thisworld
. Return a fragmentary world which can be deep-merged into this world.new-price
(new-price old stock supply demand)
If
stock
is greater than the maximum ofsupply
anddemand
, then there is surplus andold
price is too high, so shold be reduced. If lower, then it is too low and should be increased.run
(run world)
Return a world like this
world
, with quantities and prices in markets updated to reflect supply and demand.update-markets
(update-markets world)
(update-markets world city)
(update-markets world city commodity)
Return a world like this
world
, with quantities and prices in markets updated to reflect supply and demand. Ifcity
orcity
andcommodity
are specified, return a fragmentary world with only the changes for thatcity
(andcommodity
if specified) populated.cc.journeyman.the-great-game.merchants.merchant-utils documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html new file mode 100644 index 0000000..95367d6 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.merchants.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.merchants.merchant-utils
Useful functions for doing low-level things with merchants.
add-known-prices
(add-known-prices merchant world)
Add the current prices at this
merchant
’s location in theworld
to a new cache of known prices, and return it.add-stock
(add-stock a b)
Where
a
andb
are both maps all of whose values are numbers, return a map whose keys are a union of the keys ofa
andb
and whose values are the sums of their respective values.burden
(burden merchant world)
The total weight of the current cargo carried by this
merchant
in thisworld
.can-afford
(can-afford merchant world commodity)
Return the number of units of this
commodity
which thismerchant
can afford to buy in thisworld
.can-carry
(can-carry merchant world commodity)
Return the number of units of this
commodity
which thismerchant
can carry in thisworld
, given their current burden.expected-price
(expected-price merchant commodity city)
Find the price anticipated, given this
world
, by thismerchant
for thiscommodity
in thiscity
. If no information, assume 1.merchant
should be passed as a map,commodity
andcity
should be passed as keywords.cc.journeyman.the-great-game.merchants.merchants documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.planning.html b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html new file mode 100644 index 0000000..e10daee --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.planning.html @@ -0,0 +1,26 @@ + +cc.journeyman.the-great-game.merchants.merchants
Trade planning for merchants, primarily.
cc.journeyman.the-great-game.merchants.planning documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html new file mode 100644 index 0000000..7494b88 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.merchants.strategies.simple.html @@ -0,0 +1,4 @@ + +cc.journeyman.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.
augment-plan
(augment-plan merchant world plan)
Augment this
+plan
constructed in thisworld
for thismerchant
with the:quantity
of goods which should be bought and the:expected-profit
of the trade.Returns the augmented plan.
generate-trade-plans
(generate-trade-plans merchant world commodity)
Generate all possible trade plans for this
+merchant
and thiscommodity
in thisworld
.Returned plans are maps with keys:
+-
+
nearest-with-targets
(nearest-with-targets plans targets)
Return the distance to the nearest destination among those of these
plans
which match thesetargets
. Plans are expected to be plans as returned bygenerate-trade-plans
, q.v.;targets
are expected to be as accepted bymake-target-filter
, q.v.plan-trade
(plan-trade merchant world commodity)
Find the best destination in this
+world
for thiscommodity
given thismerchant
and thisorigin
. If two cities are anticipated to offer the same price, the nearer should be preferred; if two are equally distant, the ones nearer to the merchant’s home should be preferred.merchant
may be passed as a map or a keyword;commodity
should be passed as a keyword.The returned plan is a map with keys:
+-
+
select-cargo
(select-cargo merchant world)
A
merchant
, in a given location in aworld
, will choose to buy a cargo within the limit they are capable of carrying, which they can anticipate selling for a profit at a destination.cc.journeyman.the-great-game.merchants.strategies.simple documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.objects.container.html b/docs/codox/cc.journeyman.the-great-game.objects.container.html new file mode 100644 index 0000000..a062605 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.objects.container.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.merchants.strategies.simple
Default trading strategy for merchants.
+The simple strategy buys a single product in the local market if there is one which can be traded profitably, trades it to the chosen target market, and sells it there. If there is no commodity locally which can be traded profitably, moves towards home with no cargo. If at home and no commodity can be traded profitably, does not move.
move-merchant
(move-merchant merchant world)
Handle general en route movement of this
merchant
in thisworld
; return a (partial or full) world like thisworld
but in which the merchant may have been moved ot updated.plan-and-buy
(plan-and-buy merchant world)
Return a world like this
world
, in which thismerchant
has planned a new trade, and bought appropriate stock for it. If no profitable trade can be planned, the merchant is simply moved towards their home.re-plan
(re-plan merchant world)
Having failed to sell a cargo at current location, re-plan a route to sell the current cargo. Returns a revised world.
sell-and-buy
(sell-and-buy merchant world)
Return a new world like this
world
, in which thismerchant
has sold their current stock in their current location, and planned a new trade, and bought appropriate stock for it.cc.journeyman.the-great-game.objects.container documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.objects.game-object.html b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html new file mode 100644 index 0000000..3641488 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.objects.game-object.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.objects.container
TODO: write docs
ProtoContainer
protocol
members
contents
(contents container)
Return a sequence of the contents of this
container
, ornil
if empty.is-empty?
(is-empty? container)
Return
true
if thiscontainer
is empty, elsefalse
.cc.journeyman.the-great-game.objects.game-object documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.playroom.html b/docs/codox/cc.journeyman.the-great-game.playroom.html new file mode 100644 index 0000000..fe8bbe5 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.playroom.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.objects.game-object
Anything at all in the game world
ProtoObject
protocol
An object in the world
members
id
(id object)
Returns the unique id of this object.
reify-object
(reify-object object)
Adds this
object
to the global object list. If theobject
has a non-nil value for itsid
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.cc.journeyman.the-great-game.playroom documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.time.html b/docs/codox/cc.journeyman.the-great-game.time.html new file mode 100644 index 0000000..ee9153c --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.time.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.playroom
TODO: write docs
cc.journeyman.the-great-game.time documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.utils.html b/docs/codox/cc.journeyman.the-great-game.utils.html new file mode 100644 index 0000000..d44da8a --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.utils.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.time
TODO: write docs
date-string
(date-string game-time)
Return a correctly formatted date for this
game-time
in the calendar of the Great Place.day-of-year
macro
(day-of-year game-time)
The day of the year represented by this
game-time
, ignoring leap years.days-of-week
The eight-day week of the game world. This differs from the canonical ordering of houses in that it omits the eye.
game-day-length
The Java clock advances in milliseconds, which is fine. But we need game-days to be shorter than real world days. A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is presumably researched. Round it up to 100 minutes for easier calculation.
game-time
(game-time)
(game-time timestamp)
With no arguments, the current game time. If a Java
timestamp
value is passed (as along
), the game time represented by that value.now
(now)
For now, we’ll use Java timestamp for time; ultimately, we need a concept of game-time which allows us to drive day/night cycle, seasons, et cetera, but what matters about time is that it is a value which increases.
seasons-in-year
Nine seasons in a year, one for each house (although the order is different.
seasons-of-year
The ordering of seasons in the year is different from the canonical ordering of the houses, for reasons of the agricultural cycle.
weeks-in-season
To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.
weeks-of-season
To fit nine seasons of eight day weeks into 365 days, each must be of five weeks.
cc.journeyman.the-great-game.utils documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.heightmap.html b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html new file mode 100644 index 0000000..8263851 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.heightmap.html @@ -0,0 +1,5 @@ + +cc.journeyman.the-great-game.utils
TODO: write docs
deep-merge
(deep-merge & maps)
Recursively merges maps. Stolen from https://dnaeon.github.io/recursively-merging-maps-in-clojure/
make-target-filter
(make-target-filter targets)
Construct a filter which, when applied to a list of maps, will pass those which match these
targets
, where each target is a tuple [key value].value-or-default
(value-or-default m k dflt)
Return the value of this key
k
in this mapm
, or thisdflt
value if there is none.cc.journeyman.the-great-game.world.heightmap documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.location.html b/docs/codox/cc.journeyman.the-great-game.world.location.html new file mode 100644 index 0000000..c924791 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.location.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.heightmap
Functions dealing with the tessellated multi-layer heightmap.
excerpt-grid
(excerpt-grid grid x-offset y-offset width height)
Return that section of this
grid
where the:x
co-ordinate of each cell is greater than or equal to thisx-offset
, the:y
co-ordinate is greater than or equal to thisy-offset
, whose width is not greater than thiswidth
, and whose height is not greater than thisheight
.get-surface
(get-surface cell-size x-offset y-offset width height)
(get-surface base-map noise-map cell-size x-offset y-offset width height)
Return, as a vector of vectors of cells represented as Clojure maps, a segment of surface from this
+base-map
as modified by thisnoise-map
at thiscell-size
starting at thisx-offset
andy-offset
and having thiswidth
andheight
.If
+base-map
andnoise-map
are not supplied, the bindings of*base-map*
and*noise-map*
will be used, respectively.base-map
andnoise-map
may be passed either as strings, assumed to be file paths of PNG files, or as MicroWorld style world arrays. It is assumed that one pixel inbase-map
represents one square kilometre in the game world. It is assumed thatcell-size
,x-offset
,y-offset
,width
andheight
are integer numbers of metres.interpolate-altitude
(interpolate-altitude cell grid src-width x-offset y-offset)
Return the altitude of the point at
x-offset
,y-offset
within thiscell
having thissrc-width
, taken from thisgrid
.interpolate-cell
(interpolate-cell cell grid src-width target-width)
Construct a grid (array of arrays) of cells each of width
target-width
from thiscell
, of widthsrc-width
, taken from thisgrid
interpolate-grid
(interpolate-grid grid src-width target-width)
Return a grid interpolated from this
grid
of rows, cols given scaling from thissrc-width
to thistarget-width
cc.journeyman.the-great-game.world.location documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.mw.html b/docs/codox/cc.journeyman.the-great-game.world.mw.html new file mode 100644 index 0000000..ffa00f5 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.mw.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.location
Functions dealing with location in the world.
get-coords
(get-coords location)
Return the coordinates in the game world of
location
, which may be 1. A coordinate pair in the format {:x 5 :y 32}; 2. A location, as discussed above; 3. Any other gameworld object, having a:location
property whose value is one of the above.cc.journeyman.the-great-game.world.mw documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.routes.html b/docs/codox/cc.journeyman.the-great-game.world.routes.html new file mode 100644 index 0000000..0dd22cb --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.routes.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.mw
Functions dealing with building a great game world from a MicroWorld world.
cc.journeyman.the-great-game.world.routes documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.run.html b/docs/codox/cc.journeyman.the-great-game.world.run.html new file mode 100644 index 0000000..47a7e63 --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.run.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.routes
Conceptual (plan level) routes, represented as tuples of location ids.
find-route
(find-route world-or-routes from to)
Find a single route from
from
toto
in thisworld-or-routes
, which may be either a world as defined in the-great-game.world.world or else a sequence of tuples of keywords.find-routes
(find-routes routes from)
(find-routes routes from to)
(find-routes routes from to steps)
Find routes from among these
routes
fromfrom
; ifto
is supplied, toto
, by breadth-first search.cc.journeyman.the-great-game.world.run documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/cc.journeyman.the-great-game.world.world.html b/docs/codox/cc.journeyman.the-great-game.world.world.html new file mode 100644 index 0000000..f5064bf --- /dev/null +++ b/docs/codox/cc.journeyman.the-great-game.world.world.html @@ -0,0 +1,3 @@ + +cc.journeyman.the-great-game.world.run
Run the whole simulation
run
(run world)
(run world date)
The pipeline to run the simulation each game day. Returns a world like this world, with all the various active elements updated. The optional
date
argument, if supplied, is set as the:date
of the returned world.cc.journeyman.the-great-game.world.world documentation Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/economy.html b/docs/codox/economy.html index 9bd68f7..b60378d 100644 --- a/docs/codox/economy.html +++ b/docs/codox/economy.html @@ -1,6 +1,6 @@ -cc.journeyman.the-great-game.world.world
Access to data about the world
actual-price
(actual-price world commodity city)
Find the actual current price of this
commodity
in thiscity
given thisworld
. NOTE that merchants can only know the actual prices in the city in which they are currently located.run
(run world)
(run world date)
Return a world like this
world
with only the:date
to thisdate
(or iddate
not supplied, the current value incremented by one). For running other aspects of the simulation, see the-great-game.world.run.Game world economy Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Game world economy
+Game world economy Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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 2d0f0d2..c5e9a95 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -The-great-game 0.1.2-SNAPSHOT Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file +The-great-game 0.1.2-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:
[journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]
Topics
Namespaces
the-great-game.gossip.gossip
Interchange of news events between gossip agents
Public variables and functions:
the-great-game.gossip.news-items
Categories of news events interesting to gossip agents
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.
Public variables and functions:
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.
Public variables and functions:
the-great-game.merchants.strategies.simple
Default trading strategy for merchants.
Public variables and functions:
the-great-game.time
TODO: write docs
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 0.1.2-SNAPSHOT Generated by Codox
The-great-game 0.1.2-SNAPSHOT
\ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html index 708ac64..2b59e00 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,6 +1,6 @@ -The-great-game 0.1.2-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:
[journeyman-cc/the-great-game "0.1.2-SNAPSHOT"]
Topics
Namespaces
cc.journeyman.the-great-game.agent.agent
Anything in the game world with agency; primarily but not exclusively characters.
Public variables and functions:
cc.journeyman.the-great-game.buildings.module
A module of a building; essentially something like a portacabin, which can be assembled together with other modules to make a complete building.
Public variables and functions:
cc.journeyman.the-great-game.buildings.rectangular
Build buildings with a generally rectangular floow plan.
Public variables and functions:
cc.journeyman.the-great-game.gossip.gossip
Interchange of news events between gossip agents.
Public variables and functions:
cc.journeyman.the-great-game.gossip.news-items
Categories of news events interesting to gossip agents.
Public variables and functions:
cc.journeyman.the-great-game.merchants.markets
Adjusting quantities and prices in markets.
Public variables and functions:
cc.journeyman.the-great-game.merchants.merchant-utils
Useful functions for doing low-level things with merchants.
Public variables and functions:
cc.journeyman.the-great-game.merchants.merchants
Trade planning for merchants, primarily.
Public variables and functions:
cc.journeyman.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.
Public variables and functions:
cc.journeyman.the-great-game.merchants.strategies.simple
Default trading strategy for merchants.
Public variables and functions:
cc.journeyman.the-great-game.objects.game-object
Anything at all in the game world
Public variables and functions:
cc.journeyman.the-great-game.time
TODO: write docs
cc.journeyman.the-great-game.world.heightmap
Functions dealing with the tessellated multi-layer heightmap.
Public variables and functions:
cc.journeyman.the-great-game.world.location
Functions dealing with location in the world.
Public variables and functions:
cc.journeyman.the-great-game.world.mw
Functions dealing with building a great game world from a MicroWorld world.
Public variables and functions:
cc.journeyman.the-great-game.world.routes
Conceptual (plan level) routes, represented as tuples of location ids.
Public variables and functions:
cc.journeyman.the-great-game.world.run
Run the whole simulation
cc.journeyman.the-great-game.world.world
Access to data about the world
Public variables and functions:
Introduction to the-great-game Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Introduction to the-great-game
+Introduction to the-great-game Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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 0e4b71a..a747227 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 Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Modelling trading cost and risk
+Modelling trading cost and risk Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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 d36f96d..fc52305 100644 --- a/docs/codox/naming-of-characters.html +++ b/docs/codox/naming-of-characters.html @@ -1,6 +1,6 @@ -Naming of Characters Generated by Codox
The-great-game 0.1.2-SNAPSHOT
Naming of Characters
+Naming of Characters Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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 4dbc411..67198d7 100644 --- a/docs/codox/on-dying.html +++ b/docs/codox/on-dying.html @@ -1,7 +1,6 @@ -On Dying Generated by Codox
The-great-game 0.1.2-SNAPSHOT
On Dying
-On Dying Generated by Codox
The-great-game 0.1.1
On Dying
+On Dying Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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/sandbox.html b/docs/codox/sandbox.html index 6b51109..0583831 100644 --- a/docs/codox/sandbox.html +++ b/docs/codox/sandbox.html @@ -1,6 +1,6 @@ -Sandbox Generated by Codox
The-great-game 0.1.1
Sandbox
+Sandbox Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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 901ec84..d6c4a8c 100644 --- a/docs/codox/sexual-dimorphism.html +++ b/docs/codox/sexual-dimorphism.html @@ -1,6 +1,6 @@ -Sexual dimorphism Generated by Codox
The-great-game 0.1.1
Sexual dimorphism
+Sexual dimorphism Generated by Codox
The-great-game 0.1.2-SNAPSHOT
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/src/the_great_game/architecture.md b/src/cc/journeyman/architecture.md similarity index 100% rename from src/the_great_game/architecture.md rename to src/cc/journeyman/architecture.md diff --git a/src/cc/journeyman/the_great_game/buildings/module.clj b/src/cc/journeyman/the_great_game/buildings/module.clj new file mode 100644 index 0000000..6791e9f --- /dev/null +++ b/src/cc/journeyman/the_great_game/buildings/module.clj @@ -0,0 +1,81 @@ +(ns cc.journeyman.the-great-game.buildings.module + + "A module of a building; essentially something like a portacabin, which can be + assembled together with other modules to make a complete building. + + Modules need to include + + 1. Ground floor modules, having external doors; + 2. Craft modules -- workshops -- which will normally be ground floor (except + weavers) and may have the constraint that no upper floor module can cover them; + 3. Upper floor modules, having NO external doors (but linking internal doors); + 4. Roof modules + + **Role** must be one of: + + 1. `:primary` a ground floor main entrance module + 2. `:secondary` a module which can be upper or ground floor + 3. `:upper` a module which can only be on an upper floor, for example one + with a projecting gallery, balcony or overhang. + + Other values for `role` will emerge. + + **Exits** must be a sequence of keywords taken from the following list: + + 1. `:left` an exit in the centre of the left wall + 2. `:left-front` an exit in the centre of the left half of the front wall + 3. `:front` an exit in the centre of the front wall + 4. `:right-front` an exit in the centre of the right half of the front wall + 5. `:right` an exit in the centre of the right wall + 6. `:right-back` an exit in the centre of the right half of the back wall + 7. `:left-back` an exit in the centre of the back wall + + A module placed on an upper floor must have no exit which opens beyond the + footprint of the floor below - no doors into mid air! However, it is allowable + (and indeed is necessary) to allow doors into roof spaces if the adjacent + module on the same floor does not yet exist, since otherwise it would be + impossible to access a new room which might later be built there. + + **Load** must be a small integer indicating both the weight of the module and + the total amount of weight it can support. So for example a stone-built module + might have a `load` value of 4, a brick built one of 3, and a half-timbered one + of 2, and a tent of 0. This means a stone ground floor module could support one + further floor of stone or brick, or two further floors of half timbered + construction; while a brick built ground floor could support a single brick or + half-timbered upper floor but not a stone one, and a half-timbered ground floor + could only support a half timbered upper floor. + + There also needs to be an undercroft or platform module, such that the area of + the top of the platform is identical with the footprint of the building, and + the altitude of the top of the platform is equal to the altitude of the + terrain at the heighest corner of the building; so that the actual + building doesn't float in the air, and also so that none of the doors or windows + are partly underground. + + Each module needs to wrap an actual 3d model created in Blender or whatever, + and have a list of optional **textures** with which that model can be rendered. + So an upper floor bedroom module might have the following renders: + + 1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture + 2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture + 3. Half-timbered - not available on plateau terrain + 4. Weatherboarded - constrained to forest terrain + 5. Brick - constrained to arable or arid terrain + + of course these are only examples, and also, it's entirely possible to have + for example multiple different weatherboard renders for the same module. + There needs to be a way of rendering what can be built above what: for + example, you can't have a masonry clad module over a half timbered one, + but you can have a half-timbered one over a masonry one.") + +(defrecord BuildingModule + [model + ^Double length + ^Double width + ^Double height + ^Integer load + ^clojure.lang.Keyword role + ^clojure.lang.IPersistentCollection textures + ^clojure.lang.IPersistentCollection exits + ] + ) \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/buildings/rectangular.clj b/src/cc/journeyman/the_great_game/buildings/rectangular.clj index 17a2c13..1000a6d 100644 --- a/src/cc/journeyman/the_great_game/buildings/rectangular.clj +++ b/src/cc/journeyman/the_great_game/buildings/rectangular.clj @@ -1,84 +1,86 @@ (ns cc.journeyman.the-great-game.buildings.rectangular + "Build buildings with a generally rectangular floow plan. + + ## Motivations + + Right, the idea behind this namespace is many fold. + + 1. To establish the broad principle of genetic buildings, by creating a + function which reproducibly creates reproducible buildings at specified + locations, such that different buildings are credibly varied but a + building at a specified location is always (modulo economic change) the + same. + 2. Create good rectangular buildings, and investigate whether a single + function can be used to create buildings of more than one family (e.g. + can it produce flat roofed, north African style, mud brick houses as + well as pitch roofed, half timbered northern European houses?) + 3. Establish whether, in my current state of fairly severe mental illness, + I can actually produce any usable code at all. + + ## Key factors in the creation of a building + + ### Holding + + Every building is on a holding, and, indeed, what I mean by 'building' here + may well turn out to be 'the collection of all the permanent structures on + a holding. A holding is a polygonal area of the map which does not + intersect with any other holding, but for the time being we'll make the + simplifying assumption that every holding is a rectangular strip, and that + 'urban' holdings are of a reasonably standard width (see Viking-period + York) and length. Rural holdings (farms, ?wood lots) may be much larger. + + ### Terrain + + A building is made of the stuff of the place. In a forest, buildings will + tend to be wooden; in a terrain with rocky outcrops -- normally found on + steep slopes -- stone. On the flat lands where there's river mud, of brick, + cob, or wattle and daub. So to build a building we need to know the + terrain. Terrain can be inferred from location but in practice this will + be computationally expensive, so we'll pass terrain in as an argument to + the build function. + + For the time being we'll pass it in simply as a keyword from a defined set + of keywords; later it may be a more sophisticated data structure. + + ### Culture + + People of different cultures build distinctively different buildings, even + when using the same materials. So, in our world, a Japanese wooden house + looks quite different from an Anglo Saxon stave house which looks quite + different from a Canadian log cabin, even though the materials are much the + same and the tools available to build with are not much different. + + Culture can affect not just the overall shape of a building but also its + finish and surface detail. For example, in many places in England, stone + buildings are typically left bare; in rural Scotland, typically painted + white or in pastel shades; in Ireland, often quite vivid colours. + + People may also show religious or cultural symbols on their buildings. + + For all these reasons, we need to know the culture of the occupant when + creating a building. Again, this will initially be passed in as a keyword. + + ### Craft + + People in the game world have a craft, and some crafts will require + different features in the building. In the broadly late-bronze-age-to + medieval period within which the game is set, residence and workplace + are for most people pretty much the same. + + So a baker needs an oven, a smith a forge, and so on. All crafts who do + some degree retail trade will want a shop front as part of the ground + floor of their dwelling. Merchants and bankers will probably have houses + that are a bit more showy than others. + + Whether the 'genetic buildings' idea will ever really produce suitable + buildings for aristons I don't know; it seems more likely that significant + strongholds (of which there will be relatively few) should all be hand + modelled rather than procedurally generated." (:require [cc.journeyman.the-great-game.holdings.holding :refer [ProtoHolding]] - [cc.journeyman.the-great-game.location.location :refer [ProtoLocation]] - ) - (:import [org.apache.commons.math3.random MersenneTwister] - )) - -;;; Right, the idea behind this namespace is many fold. -;;; -;;; 1. To establish the broad principle of genetic buildings, by creating a -;;; function which reproducibly creates reproducible buildings at specified -;;; locations, such that different buildings are credibly varied but a -;;; building at a specified location is always (modulo economic change) the -;;; same. -;;; 2. Create good rectangular buildings, and investigate whether a single -;;; function can be used to create buildings of more than one family (e.g. -;;; can it produce flat roofed, north African style, mud brick houses as -;;; well as pitch roofed, half timbered northern European houses?) -;;; 3. Establish whether, in my current state of fairly severe mental illness, -;;; I can actually produce any usable code at all. -;;; -;;; ## Key factors in the creation of a building -;;; -;;; ### Holding -;;; -;;; Every building is on a holding, and, indeed, what I mean by 'building' here -;;; may well turn out to be 'the collection of all the permanent structures on -;;; a holding. A holding is a polygonal area of the map which does not -;;; intersect with any other holding, but for the time being we'll make the -;;; simplifying assumption that every holding is a rectangular strip, and that -;;; 'urban' holdings are of a reasonably standard width (see Viking-period -;;; York) and length. Rural holdings (farms, ?wood lots) may be much larger. -;;; -;;; ### Terrain -;;; -;;; A building is made of the stuff of the place. In a forest, buildings will -;;; tend to be wooden; in a terrain with rocky outcrops -- normally found on -;;; steep slopes -- stone. On the flat lands where there's river mud, of brick, -;;; cob, or wattle and daub. So to build a building we need to know the -;;; terrain. Terrain can be inferred from location but in practice this will -;;; be computationally expensive, so we'll pass terrain in as an argument to -;;; the build function. -;;; -;;; For the time being we'll pass it in simply as a keyword from a defined set -;;; of keywords; later it may be a more sophisticated data structure. -;;; -;;; ### Culture -;;; -;;; People of different cultures build distinctively different buildings, even -;;; when using the same materials. So, in our world, a Japanese wooden house -;;; looks quite different from an Anglo Saxon stave house which looks quite -;;; different from a Canadian log cabin, even though the materials are much the -;;; same and the tools available to build with are not much different. -;;; -;;; Culture can affect not just the overall shape of a building but also its -;;; finish and surface detail. For example, in many places in England, stone -;;; buildings are typically left bare; in rural Scotland, typically painted -;;; white or in pastel shades; in Ireland, often quite vivid colours. -;;; -;;; People may also show religious or cultural symbols on their buildings. -;;; -;;; For all these reasons, we need to know the culture of the occupant when -;;; creating a building. Again, this will initially be passed in as a keyword. -;;; -;;; ### Craft -;;; -;;; People in the game world have a craft, and some crafts will require -;;; different features in the building. In the broadly late-bronze-age-to -;;; medieval period within which the game is set, residence and workplace -;;; are for most people pretty much the same. -;;; -;;; So a baker needs an oven, a smith a forge, and so on. All crafts who do -;;; some degree retail trade will want a shop front as part of the ground -;;; floor of their dwelling. Merchants and bankers will probably have houses -;;; that are a bit more showy than others. -;;; -;;; Whether the 'genetic buildings' idea will ever really produce suitable -;;; buildings for aristons I don't know; it seems more likely that significant -;;; strongholds (of which there will be relatively few) should all be hand -;;; modelled rather than procedurally generated. + [cc.journeyman.the-great-game.location.location :refer [ProtoLocation]]) + (:import [org.apache.commons.math3.random MersenneTwister])) + (def ^:dynamic *terrain-types* "Types of terrain which affect building families. TODO: This is a placeholder; a more sophisticated model will be needed." @@ -94,6 +96,16 @@ #{:baker :banker :butcher :chancellor :innkeeper :lawyer :magus :merchant :miller :priest :scholar :smith :weaver}) (def ^:dynamic *building-families* + "Families of buildings. + + Each family has + + * terrain types to which it is appropriate; + * crafts to which it is appropriate; + * cultures to which it is appropriate. + + Each generated building will be of one family, and will comprise modules + taken only from that family." {:pitched-rectangular {:terrains #{:arable :forest :upland} :crafts *crafts* :cultures #{:coastal :western-clans} @@ -103,36 +115,6 @@ :cultures #{:coastal} :modules []}}) -;; TODO: So, modules need to contain -;; -;; 1. Ground floor modules, having external doors; -;; 2. Craft modules -- workshops -- which will normally be ground floor (except -;; weavers) and may have the constraint that no upper floor module can cover them; -;; 3. Upper floor modules, having NO external doors (but linking internal doors); -;; 4. Roof modules -;; -;; There also needs to be an undercroft or platform module, such that the area of -;; the top of the platform is identical with the footprint of the building, and -;; the altitude of the top of the platform is equal to the altitude of the -;; terrain at the heighest corner of the building; so that the actual -;; building doesn't float in the air, and also so that none of the doors or windows -;; are partly underground. -;; -;; Each module needs to wrap an actual 3d model created in Blender or whatever, -;; and have a list of optional textures with which that model can be rendered. -;; So an upper floor bedroom module might have the following renders: -;; -;; 1. Bare masonry - constrained to upland or plateau terrain, and to coastal culture -;; 2. Painted masonry - constrained to upland or plateau terrain, and to coastal culture -;; 3. Half-timbered - not available on plateau terrain -;; 4. Weatherboarded - constrained to forest terrain -;; 5. Brick - constrained to arable or arid terrain -;; -;; of course these are only examples, and also, it's entirely possible to have -;; for example multiple different weatherboard renders for the same module. -;; There needs to be a way of rendering what can be built above what: for -;; example, you can't have a masonry clad module over a half timbered one, -;; but you can have a half-timbered one over a masonry one (defn building-family "A building family is essentially a collection of models of building modules diff --git a/src/cc/journeyman/the_great_game/gossip/gossip.clj b/src/cc/journeyman/the_great_game/gossip/gossip.clj index ee19889..6686c36 100644 --- a/src/cc/journeyman/the_great_game/gossip/gossip.clj +++ b/src/cc/journeyman/the_great_game/gossip/gossip.clj @@ -1,11 +1,15 @@ (ns cc.journeyman.the-great-game.gossip.gossip - "Interchange of news events between gossip agents" + "Interchange of news events between gossip agents. + + Note that habitual travellers are all gossip agents; specifically, at this + stage, that means merchants. When merchants are moved we also need to + update the location of the gossip with the same key. + + Innkeepers are also gossip agents but do not typically move." (:require [cc.journeyman.the-great-game.utils :refer [deep-merge]] - [cc.journeyman.the-great-game.gossip.news-items :refer [learn-news-item]])) + [cc.journeyman.the-great-game.gossip.news-items :refer [learn-news-item]] + )) -;; Note that habitual travellers are all gossip agents; specifically, at this -;; stage, that means merchants. When merchants are moved we also need to -;; update the location of the gossip with the same key. (defn dialogue "Dialogue between an `enquirer` and an `agent` in this `world`; returns a @@ -16,30 +20,26 @@ enquirer) (defn gather-news - ([world] - (reduce - deep-merge - world - (map - #(gather-news world %) - (keys (:gossips world))))) - ([world gossip] - (let [g (cond (keyword? gossip) - (-> world :gossips gossip) - (map? gossip) - gossip)] - {:gossips - {(:id g) - (reduce + "Gather news for the specified `gossip` in this `world`." + [world gossip] + (let [g (cond (keyword? gossip) + (-> world :gossips gossip) + (map? gossip) + gossip)] + (if g + {:gossips + {(:id g) + (reduce deep-merge {} (map - #(dialogue g % world) - (remove - #( = g %) - (filter - #(= (:location %) (:location g)) - (vals (:gossips world))))))}}))) + #(dialogue g % world) + (remove + #(= g %) + (filter + #(= (:location %) (:location g)) + (vals (:gossips world))))))}} + {}))) (defn move-gossip "Return a world like this `world` but with this `gossip` moved to this @@ -63,4 +63,11 @@ "Return a world like this `world`, with news items exchanged between gossip agents." [world] - (gather-news world)) + (reduce + deep-merge + world + (map + #(gather-news world %) + (keys (:gossips world))))) + + diff --git a/src/cc/journeyman/the_great_game/gossip/news_items.clj b/src/cc/journeyman/the_great_game/gossip/news_items.clj index 988a7da..18600de 100644 --- a/src/cc/journeyman/the_great_game/gossip/news_items.clj +++ b/src/cc/journeyman/the_great_game/gossip/news_items.clj @@ -1,20 +1,30 @@ (ns cc.journeyman.the-great-game.gossip.news-items - "Categories of news events interesting to gossip agents" + "Using news items (propositions) to transfer knowledge between gossip agents. + + The ideas here are based on the essay [The spread of knowledge in a large + game world](The-spread-of-knowledge-in-a-large-game-world.html), q.v.; + they've advanced a little beyond that and will doubtless + advance further in the course of writing and debugging this namespace. + + A news item is a map with the keys: + + * `date` - the date on which the reported event happened; + * `nth-hand` - the number of agents the news item has passed through; + * `verb` - what it is that happened (key into `news-topics`); + + plus other keys taken from the `keys` value associated with the verb in + `news-topics`. + + ## Notes: + + *TODO* + This namespace at present considers the `:knowledge` of a gossip to be a flat + list of propositions, each of which must be checked every time any new + proposition is offered. This is woefully inefficient. " (:require [cc.journeyman.the-great-game.world.location :refer [distance-between]] - [cc.journeyman.the-great-game.time :refer [game-time]])) + [cc.journeyman.the-great-game.time :refer [game-time]] + [taoensso.timbre :as l])) -;; The ideas here are based on the essay 'The spread of knowledge in a large -;; game world', q.v.; they've advanced a little beyond that and will doubtless -;; advance further in the course of writing and debugging this namespace. - -;; A news item is a map with the keys: -;; -;; * `date` - the date on which the reported event happened; -;; * `nth-hand` - the number of agents the news item has passed through; -;; * `verb` - what it is that happened (key into `news-topics`); -;; -;; plus other keys taken from the `keys` value associated with the verb in -;; `news-topics` (def news-topics "Topics of interest to gossip agents. Topics are keyed in this map by @@ -30,9 +40,9 @@ action; * `price` is special to buy/sell, but of significant interest to merchants. - #### Notes: + ## Notes - ##### Characters: + ### Characters *TODO* but note that at most all the receiver can learn about a character from a news item is what the giver knows about that character, degraded by @@ -46,7 +56,7 @@ as the receiver stores only that segment which the receiver finds interesting. - ##### Locations: + ### Locations A 'location' value is a list comprising at most the x/y coordinate location and the ids of the settlement and region (possibly hierarchically) that contain @@ -56,49 +66,48 @@ It is assumed that the `:home` of a character is a location in this sense. - ##### Inferences: + ### Inferences If an agent learns that Adam has married Betty, they can infer that Betty has married Adam; if they learn that Charles killed Dorothy, that Dorothy has died. I'm not convinced that my representation of inferences here is ideal. " - { ;; A significant attack is interesting whether or not it leads to deaths - :attack {:verb :attack :keys [:actor :other :location]} + {;; A significant attack is interesting whether or not it leads to deaths + :attack {:verb :attack :keys [:actor :other :location]} ;; Deaths of characters may be interesting - :die {:verb :die :keys [:actor :location]} + :die {:verb :die :keys [:actor :location]} ;; Deliberate killings are interesting. - :kill {:verb :kill :keys [:actor :other :location] - :inferences [{:verb :die :actor :other :other :nil}]} + :kill {:verb :kill :keys [:actor :other :location] + :inferences [{:verb :die :actor :other :other :nil}]} ;; Marriages may be interesting - :marry {:verb :marry :keys [:actor :other :location] - :inferences [{:verb :marry :actor :other :other :actor}]} + :marry {:verb :marry :keys [:actor :other :location] + :inferences [{:verb :marry :actor :other :other :actor}]} ;; The end of ongoing open conflict between to characters may be interesting - :peace {:verb :peace :keys [:actor :other :location] - :inferences [{:verb :peace :actor :other :other :actor}]} + :peace {:verb :peace :keys [:actor :other :location] + :inferences [{:verb :peace :actor :other :other :actor}]} ;; Things related to the plot are interesting, but will require special ;; handling. Extra keys may be required by particular plot events. - :plot {:verb :plot :keys [:actor :other :object :location]} + :plot {:verb :plot :keys [:actor :other :object :location]} ;; Rapes are interesting. - :rape {:verb :rape :keys [:actor :other :location] + :rape {:verb :rape :keys [:actor :other :location] ;; Should you also infer from rape that actor is male and adult? - :inferences [{:verb :attack} - {:verb :sex} - {:verb :sex :actor :other :other :actor}]} + :inferences [{:verb :attack} + {:verb :sex} + {:verb :sex :actor :other :other :actor}]} ;; Merchants, especially, are interested in prices in other markets - :sell {:verb :sell :keys [:actor :other :object :location :price]} + :sell {:verb :sell :keys [:actor :other :object :location :price]} ;; Sex can juicy gossip, although not normally if the participants are in an ;; established sexual relationship. - :sex {:verb :sex :keys [:actor :other :location] - :inferences [{:verb :sex :actor :other :other :actor}]} - ;; Thefts are interesting - :steal {:verb :steal :keys [:actor :other :object :location]} + :sex {:verb :sex :keys [:actor :other :location] + :inferences [{:verb :sex :actor :other :other :actor}]} + ;; Thefts are interesting. + :steal {:verb :steal :keys [:actor :other :object :location]} ;; The succession of rulers is interesting; of respected craftsmen, ;; potentially also interesting. - :succession {:verb :succession :keys [:actor :other :location :rank]} - ;; The start of ongoing open conflict between to characters may be interesting - :war {:verb :war :keys [:actor :other :location] - :inferences [{:verb :war :actor :other :other :actor}]} - }) + :succession {:verb :succession :keys [:actor :other :location :rank]} + ;; The start of ongoing open conflict between two characters may be interesting. + :war {:verb :war :keys [:actor :other :location] + :inferences [{:verb :war :actor :other :other :actor}]}}) (defn interest-in-character @@ -108,9 +117,9 @@ documented above, they probably have to be maps, to allow for degradation." [gossip character] (count - (concat - (filter #(= (:actor % character)) (:knowledge gossip)) - (filter #(= (:other % character)) (:knowledge gossip))))) + (concat + (filter #(= (:actor % character)) (:knowledge gossip)) + (filter #(= (:other % character)) (:knowledge gossip))))) (defn interesting-character? "Boolean representation of whether this `character` is interesting to this @@ -133,22 +142,22 @@ 0) (coll? location) (reduce - + - (map - #(interest-in-location gossip %) - location)) + + + (map + #(interest-in-location gossip %) + location)) :else (count - (filter - #(some (fn [x] (= x location)) (:location %)) - (cons {:location (:home gossip)} (:knowledge gossip)))))) + (filter + #(some (fn [x] (= x location)) (:location %)) + (cons {:location (:home gossip)} (:knowledge gossip)))))) ;; (interest-in-location {:home [{0, 0} :test-home] :knowledge []} [:test-home]) (defn interesting-location? "True if the location of this news `item` is interesting to this `gossip`." - [gossip item] - (> (interest-in-location gossip (:location item)) 0)) + [gossip location] + (> (interest-in-location gossip location) 0)) (defn interesting-object? [gossip object] @@ -160,40 +169,98 @@ ;; TODO: Not yet (really) implemented true) +(defn compatible-value? + "True if `known-value` is the same as `new-value`, or, for each key present + in `new-value`, has the same value for that key. + + The rationale here is that if `new-value` contains new or different + information, it's worth learning; otherwise, not." + [new-value known-value] + (or + (= new-value known-value) + ;; TODO: some handwaving here about being a slightly better descriptor -- + ;; having more keys than might + (when (and (map? new-value) (map? known-value)) + (every? true? (map #(= (new-value %) (known-value %)) + (keys new-value)))))) + +(defn compatible-item? + "True if `new-item` is identical with, or less specific than, `known-item`. + + If we already know 'Bad Joe killed Sweet Daisy', there's no point in + learning that 'someone killed Sweet Daisy', but there is point in learning + 'someone killed Sweet Daisy _with poison_'." + [new-item known-item] + (if + (reduce + #(and %1 %2) + (map #(if + (known-item %) ;; if known-item has this key + (compatible-value? (new-item %) (known-item %)) + true) + (remove #{:nth-hand :confidence :learned-from} (keys new-item)))) + true + false)) + +(defn known-item? + "True if this news `item` is already known to this `gossip`. + + This means that the `gossip` already knows an item which identifiably has + the same _or more specific_ values for all the keys of this `item` except + `:nth-hand`, `:confidence` and `:learned-from`." + [gossip item] + (if + (reduce + #(or %1 %2) + false + (filter true? (map #(compatible-item? item %) (:knowledge gossip)))) + true + false)) + (defn interesting-item? "True if anything about this news `item` is interesting to this `gossip`." [gossip item] - (or - (interesting-character? gossip (:actor item)) - (interesting-character? gossip (:other item)) - (interesting-location? gossip (:location item)) - (interesting-object? gossip (:object item)) - (interesting-topic? gossip (:verb item)))) + (and (not (known-item? gossip item)) + (or + (interesting-character? gossip (:actor item)) + (interesting-character? gossip (:other item)) + (interesting-location? gossip (:location item)) + (interesting-object? gossip (:object item)) + (interesting-topic? gossip (:verb item))))) + +(defn inc-or-one + "If this `val` is a number, return that number incremented by one; otherwise, + return 1. TODO: should probably be in `utils`." + [val] + (if + (number? val) + (inc val) + 1)) (defn infer - "Infer a new knowledge item from this `item`, following this `rule`" + "Infer a new knowledge item from this `item`, following this `rule`." [item rule] +;; (l/info "Applying rule '" rule "' to item '" item "'") (reduce merge item (cons - {:verb (:verb rule)} - (map (fn [k] {k (apply (k rule) (list item))}) - (remove - #(= % :verb) - (keys rule)))))) + {:verb (:verb rule) + :nth-hand (inc-or-one (:nth-hand item))} + (map (fn [k] {k (item (rule k))}) + (remove + #{:verb :nth-hand} + (keys rule)))))) (declare learn-news-item) (defn make-all-inferences - "Return a list of knowledge entries that can be inferred from this news + "Return a set of knowledge entries that can be inferred from this news `item`." [item] (set - (reduce - concat - (map - #(:knowledge (learn-news-item {} (infer item %) false)) - (:inferences (news-topics (:verb item))))))) + (map + #(infer item %) + (:inferences (news-topics (:verb item)))))) (defn degrade-character "Return a character specification like this `character`, but comprising @@ -207,50 +274,48 @@ only those elements this `gossip` is interested in. If none, return `nil`." [gossip location] - (let [l (if - (coll? location) - (filter - #(when (interesting-location? gossip %) %) - location))] + (let [l (when + (coll? location) + (filter + #(when (interesting-location? gossip %) %) + location))] (when-not (empty? l) l))) (defn learn-news-item "Return a gossip like this `gossip`, which has learned this news `item` if it is of interest to them." - ;; TODO: Not yet implemented ([gossip item] (learn-news-item gossip item true)) ([gossip item follow-inferences?] (if - (interesting-item? gossip item) - (let - [g (assoc - gossip - :knowledge - (cons - (assoc - item - :nth-hand (if - (number? (:nth-hand item)) - (inc (:nth-hand item)) - 1) - :time-stamp (if - (number? (:time-stamp item)) - (:time-stamp item) - (game-time)) - :location (degrade-location gossip (:location item)) - ;; TODO: ought to maybe-degrade characters we're not yet interested in - ) - ;; TODO: ought not to add knowledge items we already have, except - ;; to replace if new item is of increased specificity - (:knowledge gossip)))] + (interesting-item? gossip item) + (let [item' (assoc + item + :nth-hand (inc-or-one (:nth-hand item)) + :time-stamp (if + (number? (:time-stamp item)) + (:time-stamp item) + (game-time)) + :location (degrade-location gossip (:location item)) + :actor (degrade-character gossip (:actor item)) + :other (degrade-character gossip (:other item)) + ;; TODO: do something to degrade confidence in the item, + ;; probably as a function of the provider's confidence in + ;; the item and the gossip's trust in the provider + ) + g (assoc + gossip + :knowledge + (cons + item' + (:knowledge gossip)))] (if follow-inferences? (assoc - g - :knowledge - (concat (:knowledge g) (make-all-inferences item))) - g)) - gossip))) + g + :knowledge + (concat (:knowledge g) (make-all-inferences item))) + g))) + gossip)) diff --git a/src/cc/journeyman/the_great_game/holdings/holding.clj b/src/cc/journeyman/the_great_game/holdings/holding.clj index 2ea7f42..a84deff 100644 --- a/src/cc/journeyman/the_great_game/holdings/holding.clj +++ b/src/cc/journeyman/the_great_game/holdings/holding.clj @@ -29,14 +29,18 @@ ;; is needed to ensure this! ProtoContainer ProtoHolding - (frontage [holding] - ;; TODO: this is WRONG, but will work for now. The frontage should - ;; be the side of the perimeter nearest to the nearest existing - ;; route. + (frontage + [holding] + "TODO: this is WRONG, but will work for now. The frontage should + be the side of the perimeter nearest to the nearest existing + route." [(first (perimeter holding)) (nth (perimeter holding) 1)]) - (building-origin [holding] - ;; TODO: again this is wrong. The default building origin - ;; should be the right hand end of the frontage when viewed - ;; from outside the holding. - (first (frontage holding))) + (building-origin + [holding] + "TODO: again this is WRONG. The default building origin for rectangular + buildings should be the right hand end of the frontage when viewed + from outside the holding. But that's not general; celtic-style circular + buildings should normally be in the centre of their holdings. So probably + building-origin becomes a method of building-family rather than of holding." + (first (frontage holding))) ProtoObject) diff --git a/src/cc/journeyman/the_great_game/location/location.clj b/src/cc/journeyman/the_great_game/location/location.clj index 4b5895f..1fdc3b9 100644 --- a/src/cc/journeyman/the_great_game/location/location.clj +++ b/src/cc/journeyman/the_great_game/location/location.clj @@ -43,5 +43,3 @@ ;; (.settlement (OrientedLocation. 123.45 543.76 12.34 0.00 {})) - -;; (OrientedLocation. 123.45 543.76 12.34 0.00 {}) \ No newline at end of file diff --git a/src/cc/journeyman/the_great_game/merchants/merchants.clj b/src/cc/journeyman/the_great_game/merchants/merchants.clj index fe0e319..a4124b4 100644 --- a/src/cc/journeyman/the_great_game/merchants/merchants.clj +++ b/src/cc/journeyman/the_great_game/merchants/merchants.clj @@ -1,8 +1,8 @@ (ns cc.journeyman.the-great-game.merchants.merchants "Trade planning for merchants, primarily." - (:require [taoensso.timbre :as l :refer [info error spy]] - [the-great-game.utils :refer [deep-merge]] - [the-great-game.merchants.strategies.simple :refer [move-merchant]])) + (:require [cc.journeyman.the-great-game.utils :refer [deep-merge]] + [cc.journeyman.the-great-game.merchants.strategies.simple :refer [move-merchant]] + [taoensso.timbre :as l])) (defn run @@ -10,18 +10,18 @@ [world] (try (reduce - deep-merge - world - (map - #(try - (let [move-fn (or - (-> world :merchants % :move-fn) - move-merchant)] - (apply move-fn (list % world))) - (catch Exception any - (l/error any "Failure while moving merchant " %) - {})) - (keys (:merchants world)))) + deep-merge + world + (map + #(try + (let [move-fn (or + (-> world :merchants % :move-fn) + move-merchant)] + (apply move-fn (list % world))) + (catch Exception any + (l/error any "Failure while moving merchant " %) + {})) + (keys (:merchants world)))) (catch Exception any (l/error any "Failure while moving merchants") world))) diff --git a/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj index 7ccbdb2..b8062f7 100644 --- a/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj +++ b/src/cc/journeyman/the_great_game/merchants/strategies/simple.clj @@ -30,7 +30,7 @@ plan (select-cargo merchant world)] (l/debug "plan-and-buy: merchant" id) (cond - (not (empty? plan)) + (seq? plan) (let [c (:commodity plan) p (* (:quantity plan) (:buy-price plan)) diff --git a/src/cc/journeyman/the_great_game/objects/game_object.clj b/src/cc/journeyman/the_great_game/objects/game_object.clj index 992b378..be497e3 100644 --- a/src/cc/journeyman/the_great_game/objects/game_object.clj +++ b/src/cc/journeyman/the_great_game/objects/game_object.clj @@ -12,8 +12,10 @@ which the object is keyed in the global object list.")) (defrecord GameObject - [id] + [id] ;; "An object in the world" ProtoObject (id [_] id) - (reify-object [object] "TODO: doesn't work yet")) + (reify-object [object] + "TODO: doesn't work yet" + object)) diff --git a/src/cc/journeyman/the_great_game/playroom.clj b/src/cc/journeyman/the_great_game/playroom.clj index a53cd1e..4ab671a 100644 --- a/src/cc/journeyman/the_great_game/playroom.clj +++ b/src/cc/journeyman/the_great_game/playroom.clj @@ -1,9 +1,13 @@ (ns cc.journeyman.the-great-game.playroom - (require [jme-clj.core :refer :all]) - (import [com.jme3.math ColorRGBA])) + (:require [jme-clj.core :refer [add add-to-root box defsimpleapp fly-cam geo + get* get-state load-texture rotate run set* + setc set-state start unshaded-mat]]) + (:import [com.jme3.math ColorRGBA])) ;; At present this file is just somewhere to play around with jme-clj examples +(declare app) + (defn init [] (let [cube (geo "jMonkey cube" (box 1 1 1)) mat (unshaded-mat)] diff --git a/src/cc/journeyman/the_great_game/world/heightmap.clj b/src/cc/journeyman/the_great_game/world/heightmap.clj index 07864ae..99369c8 100644 --- a/src/cc/journeyman/the_great_game/world/heightmap.clj +++ b/src/cc/journeyman/the_great_game/world/heightmap.clj @@ -3,7 +3,7 @@ (:require [clojure.math.numeric-tower :refer [expt sqrt]] [mw-engine.core :refer []] [mw-engine.heightmap :refer [apply-heightmap]] - [mw-engine.utils :refer [get-cell in-bounds? map-world scale-world]] + [mw-engine.utils :refer [get-cell in-bounds? map-world]] [cc.journeyman.the-great-game.utils :refer [value-or-default]])) ;; It's not at all clear to me yet what the workflow for getting a MicroWorld @@ -149,7 +149,7 @@ ([cell-size x-offset y-offset width height] (get-surface *base-map* *noise-map* cell-size x-offset y-offset width height)) ([base-map noise-map cell-size x-offset y-offset width height] - (let [b (if (seq? base-map) base-map (scale-world (apply-heightmap base-map) 1000)) + (let [b (if (seq? base-map) base-map (scale-grid (apply-heightmap base-map) 1000)) n (if (seq? noise-map) noise-map (apply-heightmap noise-map))] (if (and (in-bounds? b x-offset y-offset) (in-bounds? b (+ x-offset width) (+ y-offset height))) diff --git a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj index 79137a6..50f062a 100644 --- a/test/cc/journeyman/the_great_game/gossip/news_items_test.clj +++ b/test/cc/journeyman/the_great_game/gossip/news_items_test.clj @@ -1,135 +1,163 @@ (ns cc.journeyman.the-great-game.gossip.news-items-test - (:require [clojure.test :refer :all] - [cc.journeyman.the-great-game.gossip.news-items :refer - [degrade-location infer interest-in-location interesting-location? + (:require [clojure.test :refer [deftest is testing]] + [cc.journeyman.the-great-game.gossip.news-items :refer + [compatible-item? degrade-location infer interest-in-location interesting-location? learn-news-item make-all-inferences]])) +(deftest compatible-item-test + (testing "Compatible item: items are identical" + (let [expected true + new-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "Items which are identical are compatible."))) + (testing "Compatible item: new item is less specific" + (let [expected true + new-item {:verb :kills :location :tchahua :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) + "An item which is less specific is compatible with existing knowledge."))) + (testing "Compatible item: new item is more specific" + (let [expected true + new-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy :date 20210609} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "A new item which is more specific adds knowledge and is not compatible"))) + (testing "Compatible item: new item conflicts with existing knowledge." + (let [expected false + new-item {:verb :kills :location :tchahua :actor :jealous-joe :other :dainty-daisy} + known-item {:verb :kills :location :tchahua :actor :fierce-fred :other :dainty-daisy} + actual (compatible-item? new-item known-item)] + (is (= actual expected) "A new item which we don't yet intelligently handle but is not compatible")))) + (deftest location-test (testing "Interest in locations" (let [expected 1 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - :galloway)] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + :galloway)] (is (= actual expected))) (let [expected 2 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway :scotland]}]} - [:galloway :scotland])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway :scotland]}]} + [:galloway :scotland])] (is (= actual expected))) (let [expected 2 actual (interest-in-location - {:home [{:x 35 :y 23} :auchencairn :galloway :scotland]} - [:galloway :scotland])] + {:home [{:x 35 :y 23} :auchencairn :galloway :scotland]} + [:galloway :scotland])] (is (= actual expected))) (let [expected 0 actual (interest-in-location - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:dumfries])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:dumfries])] (is (= actual expected))) (let [expected 7071.067811865475 actual (interest-in-location - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24}])] (is (= actual expected) "TODO: 7071.067811865475 is actually a bad answer.")) (let [expected 0 actual (interest-in-location - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24000}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24000}])] (is (= actual expected) "Too far apart (> 10000).")) (let [expected true actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - :galloway)] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + :galloway)] (is (= actual expected))) (let [expected true actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:galloway :scotland])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:galloway :scotland])] (is (= actual expected))) (let [expected false actual (interesting-location? - {:knowledge [{:verb :steal - :actor :albert - :other :belinda - :object :foo - :location [{:x 35 :y 23} :auchencairn :galloway]}]} - [:dumfries])] + {:knowledge [{:verb :steal + :actor :albert + :other :belinda + :object :foo + :location [{:x 35 :y 23} :auchencairn :galloway]}]} + [:dumfries])] (is (= actual expected))) (let [expected true actual (interesting-location? - {:home [{:x 35 :y 23}]} - [{:x 34 :y 24}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 24}])] (is (= actual expected))) (let [expected false actual (interesting-location? - {:home [{:x 35 :y 23}]} - [{:x 34 :y 240000}])] + {:home [{:x 35 :y 23}]} + [{:x 34 :y 240000}])] (is (= actual expected)))) (testing "Degrading locations" (let [expected [:galloway] actual (degrade-location - {:home [{0 0} :test-home :galloway]} - [{-4 55} :auchencairn :galloway])] + {:home [{0 0} :test-home :galloway]} + [{-4 55} :auchencairn :galloway])] (is (= actual expected))) (let [expected nil actual (degrade-location - {:home [{0 0} :test-home :galloway]} - [:froboz])] + {:home [{0 0} :test-home :galloway]} + [:froboz])] (is (= actual expected))))) (deftest inference-tests (testing "Ability to infer new knowledge from news items: single rule tests" (let [expected {:verb :marry, :actor :belinda, :other :adam} - actual (infer {:verb :marry :actor :adam :other :belinda} - {:verb :marry :actor :other :other :actor})] + item {:verb :marry :actor :adam :other :belinda} + rule {:verb :marry :actor :other :other :actor} + actual (infer item rule)] (is (= actual expected))) (let [expected {:verb :attack, :actor :adam, :other :belinda} - actual (infer {:verb :rape :actor :adam :other :belinda} - {:verb :attack})] + item {:verb :rape :actor :adam :other :belinda} + rule {:verb :attack} + actual (infer item rule)] (is (= actual expected))) (let [expected {:verb :sex, :actor :belinda, :other :adam} - actual (infer {:verb :rape :actor :adam :other :belinda} - {:verb :sex :actor :other :other :actor})] + item {:verb :rape :actor :adam :other :belinda} + rule {:verb :sex :actor :other :other :actor} + actual (infer item rule)] (is (= actual expected)))) (testing "Ability to infer new knowledge from news items: all applicable rules" - (let [expected #{{:verb :sex, :actor :belinda, :other :adam, :location nil, :nth-hand 1} - {:verb :sex, :actor :adam, :other :belinda, :location nil, :nth-hand 1} - {:verb :attack, :actor :adam, :other :belinda, :location nil, :nth-hand 1}} + (let [expected #{{:verb :sex, :actor :belinda, :other :adam, :location :test-home, :nth-hand 1} + {:verb :sex, :actor :adam, :other :belinda, :location :test-home, :nth-hand 1} + {:verb :attack, :actor :adam, :other :belinda, :location :test-home, :nth-hand 1}} ;; dates will not be and cannot be expected to be equal - actual (make-all-inferences - {:verb :rape :actor :adam :other :belinda :location :test-home}) - actual' (set (map #(dissoc % :time-stamp) actual))] - (is (= actual' expected))))) + actual (set (make-all-inferences + {:verb :rape :actor :adam :other :belinda :location :test-home :nth-hand 1}))] + (is (= actual expected))))) (deftest learn-tests (testing "Learning from an interesting news item." - (let [expected {:home [{0 0} :test-home], - :knowledge [{:verb :sex, :actor :adam, :other :belinda, :location nil, :nth-hand 1} - {:verb :sex, :actor :belinda, :other :adam, :location nil, :nth-hand 1}]} + (let [expected {:home [{0 0} :test-home] + :knowledge [{:verb :sex, :actor :adam, :other :belinda, :location [:test-home], :nth-hand 1} + {:verb :sex, :actor :belinda, :other :adam, :location [:test-home], :nth-hand 1}]} actual (learn-news-item - {:home [{0, 0} :test-home] :knowledge []} - {:verb :sex :actor :adam :other :belinda :location [:test-home]}) - actual' (assoc actual :knowledge (vec (map #(dissoc % :time-stamp) (:knowledge actual))))] - (is (= actual' expected))))) + {:home [{0, 0} :test-home] :knowledge []} + {:verb :sex :actor :adam :other :belinda :location [:test-home]})] + (is (= actual expected))))) diff --git a/test/cc/journeyman/the_great_game/merchants/markets_test.clj b/test/cc/journeyman/the_great_game/merchants/markets_test.clj index e86d173..d972257 100644 --- a/test/cc/journeyman/the_great_game/merchants/markets_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/markets_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.markets-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.markets :refer [adjust-quantity-and-price new-price run]])) diff --git a/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj index 69f40fe..52766f8 100644 --- a/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/merchant_utils_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.merchant-utils-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.merchant-utils :refer diff --git a/test/cc/journeyman/the_great_game/merchants/planning_test.clj b/test/cc/journeyman/the_great_game/merchants/planning_test.clj index ef7595b..190aaf7 100644 --- a/test/cc/journeyman/the_great_game/merchants/planning_test.clj +++ b/test/cc/journeyman/the_great_game/merchants/planning_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.merchants.planning-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [cc.journeyman.the-great-game.utils :refer [deep-merge]] [cc.journeyman.the-great-game.world.world :refer [default-world]] [cc.journeyman.the-great-game.merchants.planning :refer [plan-trade select-cargo]])) diff --git a/test/cc/journeyman/the_great_game/time_test.clj b/test/cc/journeyman/the_great_game/time_test.clj index eb5d856..cbb8689 100644 --- a/test/cc/journeyman/the_great_game/time_test.clj +++ b/test/cc/journeyman/the_great_game/time_test.clj @@ -1,5 +1,5 @@ (ns cc.journeyman.the-great-game.time-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] ;; [clojure.core.async :refer [thread