Moonman has a bunch of different base areas, like Cave, Tunnel, Forest, Mountain, Town, etc. The number, type, theme, and connections between these will eventually be fairly flexible, and some of them like Cave have a number of different forms already. To further push the feeling that the world is different, we're adding randomised names to each of the areas -- things like "Quiet Cave", "Forest of Stones", "Ben's House", etc. There are a number of steps to this:
- Creating interesting words and part-words;
- Figuring out how to combine them; and,
- Giving some meaning to them, so they aren't just random labels.
To start off with Alex and I came up with a heap of different words, and we then figured out some basic ways to join them together, getting some examples like "Sacred Hill", "Ancient Grove", "Manic Icelands", and "Northland Fortress". Using this as a starting point, I then built a huge list of word parts and patterns. The patterns were of the form:
[The] <noun> examples: The Place, Cove, Tunnel
[The] <adj> <noun> examples: Red Forest, The Last Mountain, Blue Valley
<part-adj><part-noun> examples: Highhorn, Skypeak
[The] indicates an optional "The", and the
<term> indicates a specific type of word. The words were put into a big spreadsheet, like this:
Each area has a specific set of patterns, for instance the forest supports 6 or so different patterns, whereas the smaller tunnels only support 2. We split the words into area-specific and general lists, for instance when generating
[The] <adj> <noun> for a forest, the adjectives are taken a general adjective list and also a forest adjective list (the nouns are taken only from the forest nouns, shown above).
Each word also has optional tags, which will used to give some abstract sense of meaning to a name. For instance the place name "The Forest" will have the tags
treedense, meaning that the name is NOT suitable for areas that are treeless, and it is very suitable for areas that have dense trees. Some other possible tags include
The final part of that spreadsheet is the "Commonality" column, which just lets me indicate the weighting of a specific word. In this case "hill" is weighted much lower than the others so will be used more rarely.
The generation step is fairly straightforward: for each area and pattern all potential names are considered, the weights of the words are combined to give a final weighting for a place name, and the tags are combined together. Selecting a name is a process of weighted random selection, with place names being weighted further by the compatibility of their tags with the tags of the prospective area.
I implemented the generation step in Python, as I think that's the easiest tool to use for this kind of stuff. The script has a number of functions for generating the names, and a mode for inspecting the results. Here's some examples of names that can be generated (the area name is in the command line arguments):
You can also view the tags for names..
Or request the names for areas + tags...
There's also a mode that shows the individual weights of the parts. In the example below "Hill" has a weighting of 0.67 (the first column weights the optional "The" at the start of the name).
Once I had the generator running well and a decent collection of names being generated, there was the question of how to get them into the game. Moonman doesn't embed Python (or any scripting language), so the choice becomes: (a) rewrite the generator in c++, (b) pre-generate a big list of names and stick them in a data file. I went with the latter option, mainly for economy. So now there's an extra 1MB file in the data directory that contains about 20,000 pre-generated place names, along with their weights and tags. The game will read them at load-time, and then select an appropriate name from the list when a region/area is created.
See you next week!