Saturday, July 30, 2016
Any kind of soldier is considered to be training toward the fighter class, so we can consider the training they do to be the basis of training any 1st level fighter would have received. 500 XP is required to make an unleveled character combat-trained, i.e. capable as a soldier, and then a further 1000 XP is needed to become a 1st-level in any class. (The combat training and XP-before-1st-level concepts are taken from Alexis.)
This means an unleveled character being trained into a first-level fighter requires 1500 XP total; the 500 needed to acquire combat training is thus 1/3 of that total.
The base age before factoring in character class in my game is 15 years old. The starting age of a fighter in my game is 15+1d4, so the average starting age of a figher is (16+19/2) or 17.5 years old. Thus, that the average fighter took 2.5 years to gain 1500 XP. (I've assumed negligible XP is gained while reaching age 15, but that would be an interesting rabbit hole to go down some other day.)
If combat training requires 1/3 of the XP below 1st level, and likewise 1/3 of that 2.5 year average training period, then we are left with a training period of of 10 months (assuming that the first 500 and the later 1000 XP are gained at the same rate, which you may contest.) So that's a good preliminary solution.
But we can go one better. With the fighter starting age distribution actually being 16-19, we could say that the training period is 1/3 of the actual training time, whether that's 1, 2, 3, or 4 years. The corresponding training periods are 4, 8, 12, and 16 months. What's the benefit of chunking things up? Well, given a gaggle of men freshly recruited, we can say that 25% are ready to serve as soldiers after 4 months, with another 25% being available each 4 months after that. Now we have some time-based figures we can use, should the party ever decide to wage war for themselves or take sides in someone else's conflict.
Ah, but we can go one better again! Who says we have to stop at 25% divisions? Let's divide the 16-19 distribution into 8 six-month periods, then we multiply by the 1/3 time figure for training, getting a two-month period. Divide your number of recruits by 8, and that's how many new soldiers you can turn out every two months. With 100 recruits, it'd be 12 (rounded from 12.5), at first the fastest learners, then the guys who took more time to become competent. Of course, this figure is assuming that we can train all 100 soldiers at once, but there ought to also be a limit on how many recruits a single trainer (leveled fighter with skills in training others) can handle at one time. Maybe you've got a 5th level trainer and he can only handle 50 recruits -- now that 12.5 soldiers-per-month rate is cut in half.
So there's a limitation on how long it takes to turn out ready soldiers, and a limitation on how many of your conscripts can be trained simultaneously, and these two limits combine with the starting number of recruits to determine, basically, how many guys you can add to your army every two months (or each 4 months, depending on the scheme we use.) You could even go further and figure out a monthly value, if that's the time scale you want to track things in. And, of course, if you don't want to use pure percentages, you could always roll 1d4 (multiply by 4) or 1d8 (multiply by 2) for each recruit to see how long it'll take to train him.
All of this training stuff can apply even if the person being trained is not as young as 15. I'm just ballparking here, but maybe normal training rules apply to men between ages 15 and 35, and it takes more time to train anyone younger or older than that age. I'm just speculating here.
Finally, just for fun, let's compare our derived figures to modern army training. It's no fair comparison, just something to think about.
In the US Army they spend 10 weeks on basic training, and then each soldier receives a variable length of additional training depending on their assigned specialty. Infantrymen do 14 weeks. That makes a total of 24 weeks, or 6 months, of training. Furthermore, this is a total of 6 months to train to what I would consider a 1st level fighter. Compare these figures to the average 10 months of training needed to get a combat-trained unleveled soldier, or the average 2.5 years needed to get a 1st level fighter. It's quite a difference, as it should be, since modern training methods are backed by centuries of improvement that a medieval or Renaissance trainer would obviously not have been able to use. I think the proportions between the army figures and my training periods are near enough to call it OK: 10 weeks for basic combat training is 1/4 of 10 months; 6 months for full skills is 1/5 of the 2.5-year average.
All I need now is a figure to determine how many people willing to be soldiers are present in each settlement, as a percentage of the overall population. Assuming they're getting their training from somewhere, since they're starting employment ready to go, I'd then be able to multiply that "number of willing soldiers" times the 2-month rate and get the maximum number of soldiers available for hire each 2 months. Looking to hire an army? Better go somewhere big.
OK, I've been typing this all day. Time to let it out onto the web.
Wednesday, July 27, 2016
Thinking with Infrastructure
Just think, a few hours ago I thought I wouldn't work on D&D at all today ... but given my historical percentage of days on which I do work on D&D is, as of today, 95.5 percent (tracked over the last 267 days), I should have realized something would come out of the brainpipe.
I worked, and worked, and got more and more energetic as I added more chunks of code, and the end result is: I've added infrastructure calculations to the world data, including the spread of infrastructure out from each hex.
First, let's take a look at a view I've whipped up. Remember that the map I'm showing here is only a portion of the whole world. The darker the red color, the higher the infrastructure, and because of certain technical limitations and because I've only just written all this, everything 200 infrastructure and above gets the same color -- but most hexes aren't in that range. The highest value under the current calculations is a hex with an infrastructure of 235 -- not sure which hex it is or whether it's in this map, but I could find out.
(If you're wondering why some of the towns are in low-infra hexes: it's because I have to move the towns around. I didn't have infrastructure or civilized-wild measurements when I originally placed them.)
Now I'll explain how I arrive at these values.
Step one is to set a base infrastructure value for each hex. For now, I'm assigning it such that 1 civilized subtriangle = 1 infrastructure point awarded to the parent hex. Later on, I'll add bonuses for towns and cities.
Step two is to go through to each hex and spread out, from that hex, a fraction of its infrastructure value, in all directions. Finding the fraction for spreading infrastructure from hex A to hex B is calculated like this:
(base infrastructure value at the hex) / (sum of all wilderness levels in hex A + the difference in elevation bands between hex A and hex B)
Then that value-to-be-spread is added to the EVENTUAL value at B. What do I mean by eventual value? I mean that when the whole procedure has completed, for each hex, in each of the six hexagonal directions, then the accumulated eventual value (which might have been added to several times, by several different iterations of the procedure) is all added at once to the original base value at B. I do things in this way so that the value spread from A to B is always calculated from the original infra value at A, and has not had any of the intermediate values added to it. Otherwise the value which is spread from hex A would depend on whether any other hexes have given it a shot of infrastructure yet! And that would mean that how much infrastructure a hex ends up with would be predicated on the order in which each hex is processed through the system. That's something to avoid at all costs.
I hope that's all clear, but if not, ask away. I'm just typing this all out as it comes to me.
Sunday, July 24, 2016
I find this fascinating. and I could imagine this inspiring many different great bits of D&D play. I'd hesitate to go the traditional "animated skeleton" route with such a jeweled skeleton, but if I did, the implications of a saintly skeleton being brought to life would be quite fun to play out. Or another route: how many players, do you think, would expect skeleton-venerating villagers to be anything other than generic cultists? Here's a chance to throw away the boring pulp-fiction "evil death cultist" thing in favor of something more layered.
Saturday, July 23, 2016
I've been adding to the codebase the expansions I'll need in order to do road and town locations based on triangles. The first chunk of edits I needed to do for that was also just what I needed in order to add something new to the civilized-wild distinction. Have a look at the latest map image; as usual, I recommend opening it in a new tab to see it full size.
Wilderness triangles are now divided into categories 1 through 4; on the map, these are indicated as bright green, olive green, deep forest green, and red-brown. The higher the rating, the more wild and savage that part of the wilderness is. What determines the rating is how many other wild triangles border the given triangle.
The next phase would be to have the initial 1-4 rating of triangles in each hex propagate a fraction of their value into neighboring hexes' triangles, influencing their ratings. In other words, the wilderness points would be distributed across the hex grid, similar to my method of blowing moisture inland from the oceans during the world-generation step. Therefore, the final wilderness ratings would take on values between the integers 1-4, and some hexes' wilderness ratings would go far beyond the previous cap of 4.
Such an upgrade would result in patterns of wild and extremely wild areas which would measure the opposite of what infrastructure measures -- and would certainly influence a hex's base infrastructure value.
While working on this I also decided to make all water hexes all-wild (type 1); this is OK because now, with degrees of wilderness, sea triangles next to shore will be rated at the lowest wilderness rating, meaning they are the closest type of wilderness to being civilized.
If I used the wilderness rating propagation proposed above, then, given the way I'm doing sea hexes, the deep and distant parts of the ocean would be extremely dangerous.
Wednesday, July 20, 2016
Wild and Civilized Areas
I've successfully added the render layer which displays civilized and wilderness triangles.
I can already see I'm going to have to move some towns around, in order to put them into hexes with all civilized hexes. A sizable town (whether it is a castle town, or a trade town, or a religious site, or whatever) is only considered to be "possible" in a hex which I've determined to be fully civilized -- although in reality it would be the town's presence which made the area "civilized." The reason I have to work backward is because I am choosing to place cities manually; if I wanted, I could go back to random town placement, which I used to do, and have their locations be limited to only (a subset of) type 7 hexes. But I'm not going to do that.
Note that at this time water hexes are technically still being assigned civilized and wilderness triangles, but in this image I'm hiding the civ-wild visualization for them. The civ-wild distinction as currently formulated for land hexes isn't the right approach for water, I think. On the other hand, it'd be reasonable to want something resembling "civilized" triangles wherever there are shipping lanes (and patrol ships), as well as inhabited islands. I'm not sure right now just what I'm going to do about the water hexes, but I'll think of something eventually.
Tuesday, July 19, 2016
My World, Part 4: Map Renderer
No worries, though. This is the kind of hangup where I'll come back over the weekend and instantly see what needs doing. All I need do is let the idea sit untouched for a few days, and I'll think of something. As I said previously, this is not the first attempt at the triangle maker, it's just the first successful one after a few months: so what's another day or two?
In the meantime I'm going to explain how the map renderer itself works.
First, the World Generator program creates, as its primary output, three files which contain data about my game world. One file contains info on towns, another is for roads, and the third and largest contains data about the hexes themselves -- including their sub-triangles.
Each generator output file corresponds to a parser I've written in Haskell. Now what is a parser? Well, it's a type of program which consumes ordinary text and attempts to arrange it into a structured format for further manipulation. Initially, World Generator output contains chunks like "Elevation 0.133533" and "Climate Mediterranean" and "[Coord (49, -65, 16),Coord (48, -65, 17),Coord (48, -66, 18)]". However, plain old text like this isn't useful to a computer; we have to pre-specify that, for example, "Elevation 0.133533" refers to a type of data, with "Elevation" being the data constructor and "0.133533" being the value. If the string were malformed due to an error -- say that "Elevation" was spelled "Evelation" -- the parser would fail to parse, i.e. be unable to assign the structure I've specified to the text string.
Here's the structure I'm using to store information about a sub-triangle (referred to as simply a "Sub" here):
The first definition states that SubInfo is a 3-tuple. I parse that 3-tuple, and then immediately convert it into a correspondence between a Direction (definition not shown) and a Sub, specified on the next line, since I need to be able to look up that data by naming a given Direction.
Next, here's the parser which verifies input data and converts it into the above SubInfo structure.
Note that parseSubInfo is a parser which it itself composed of smaller parsers, as I've indicated with arrows. For example, parseQuality is defined as validating (and then throwing away) the string "Quality", and then doing the same with some spaces. Then it tries to validate either the word "Civilized" or the word "Wild." If successful, it converts that word into the appropriate data type (a Civilized or a Wild -- no longer a string, but a value.)
Higher up in the program I use parseSubInfo itself as a component in an even larger parser, which slurps up all the data for a single hex. This technique of combining small parsers into larger ones is extremely intuitive and straightforward; the functions here are usually referred to as parser combinators, because of their combining nature. (Moving forward, unless I say otherwise, when I say "parser" I mean the final, primary parser in each program, which may be made of smaller components.)
So: one parser for roads, one for towns, one for hexes. We use the parsers to structure the generator output into useful shapes in memory, and then pass that now-useful data into the main body of World Renderer. This program does the actual work of drawing each layer of map data into the final image. Such work includes:
- calculating the pixel coordinates at which a given hex should be drawn, based on its hex coordinates
- coloring each hex based on climate, or moisture, or elevation, or whatever else I specify from the data (thus enabling me to recreate the entire map with a new color scheme, whenever necessary)
- drawing in the roads between the locations of each town
- drawing the little town-name indicators themselves
The important part to take away is that most of what I'm doing is defining different ways to draw different data. If I added a new kind of info to each hex, all I'd have to do is specify how it should be represented as a shape or color, and I'd be ready to render a freshly improved map. I can also specify exactly which hexagons I want to render, which lets me zoom in on chunks of the world, as has been the case with the maps I've posted recently.
Here's one function from the renderer program. It calculates the output pixel coordinates for a given hexagon, based on its cubic coordinates.
And here's the primary function (one below the top-level function, which calls the parsers and then feeds their results into this function.) I think my naming conventions make it clear what is going on: we draw the hexes, then we draw the roads on top of them, then we write the town names on top of that. Note that we don't need to draw the town names before the roads, since although they haven't been rendered yet, we still have their locations in memory as part of the road info. Also note that the definition for "filtered" is how I restrict the render to a certain section of the whole ("wanted" is defined elsewhere.)
I give the renderer executable program a filename and it draws the map into that file. And that's all there is to it!
For the record, the last step is the one I'm stuck in for the civilized/wild triangle data. I'm having difficulty specifying exactly the right commands to extract triangle data for each hex and color them appropriately. Everything's parsed and ready; the renderer just needs its new drawing commands. Now you have an idea of how close I am to nailing this!
Please speak up if I've piqued your interest or if something's unclear.
Sunday, July 17, 2016
Time for some Triangles
If you can't see it right now, here's what I've done: I've subdivided each of my game world hexes into triangles. Six equal triangles. This is a stepping stone toward greater detail and variation in the design of my world. I could go on from here to have intra-hex elevation or climate variation, rework the distance algorithm for resource pricing to get more exact numbers, or do something else entirely.
Let's go for that third option. One other example usage is that, with the underpinnings of geographic separation firmly in place, I am now working to implement a system somewhat like the interrelated systems of hex groups and wilderness features that Alexis describes in these and other posts:
The idea (for my system) is that we can divide the six triangles into civilized and wilderness (broadly speaking), and then generate a combination of triangles for each map hex. This can then be used as one avenue for determination of such hex details as infrastructure, the presence of monstrous (non-human) civilization, quality of roads, and all kinds of other things. The exact configuration for each hex would be determined randomly, perhaps on a pair of dice.
Do remember that each hex measures 20 miles (from one face to another), and thus there are about 346 square miles per hexagon. Since each triangle is 1/6th of the hexagon's area, each triangle thus represents a little less than 58 square miles, with each triangle being ten miles "high" (base to tip). A single triangle, full of wilderness, is quite an area to explore even for a large group. For a typical single- or double-digits party of characters and their retainers? It would take a long time. Not to mention how difficult it would be to have any idea whatsoever that other groups were present in some other part of the hex. An army could easily pass through the triangle the party was in, at a distance of 40 miles, and the party would be none the wiser.
Let's go over the possible configurations of triangles without yet assigning any meanings to the particular arrangements. (I have to think about that some more, and consider what kinds of details I want to be produced for my world without my having to pull them from my butt.)
First we see type 1 and type 2 hexes.
A type 1 hex has only wilderness areas; any civilization here is non-human. Type 2 has one civilized hex. That hex could be any of the six hexes, which is why I say there are 6 rotated versions of this type. Thus, adding type 1 and 2 together, so far there are 7 types of hex.
Type 3 has two civilized hexes. They might be right next to each other, separated by one hex, or separated by two hexes. Note that the rotation figures given above (a total of 15) would be increased (6 more of the second kind and 3 more of the third kind) if we decided that it mattered which triangle was where. This would be the case if, for example, there was some feature which was placed only on the civilized triangle clockwise from the lone wilderness triangle. I'll disregard this kind of permutation for the rest of the post, since it depends on use and placement of hex features, which are not the focus of discussion for today.
After type 3, total arrangements are at 22.
Type 4 has three civilized sections. There are 20 possible arrangements, bringing our total to 42.
Finally, types 5, 6, and 7 are the same as types 3, 2, and 1, but with the wilderness and civilized triangles reversed. This adds another 22 triangle arrangements, bringing the final total to 64 different arrangements of triangles, each spelling out a different set of possibilities and probabilities. Does this hex contain a monastery? Is there abundant game in this area? Is the nearby wood home to a druid? Perhaps an area that's wild enough is guaranteed to contain a small dungeon, and a type-1 has a chance of containing a larger, more sinister location.
I'm planning to use a 2d6 roll to choose between each kind of hex, with further random rolls to determine the exact realization of each hex type. For example, if the 2d6 roll gives a type 2, then there's a further 1d6 roll to figure out which of the triangles is civilized. (It's all going to be automated, of course.)
OK. You've seen the triangles above, but where is the final product, with all triangles filled in as civilized or as wilderness on my hex map? Well, I haven't finished implementing it yet. I've only just gotten the triangles working, and this final, successful attempt to do that is my third such attempt in total over the last few months. (My earliest notes on this way of tackling sub-hex units are from around April.) Finally nailed it this week. Anyway: once I've got the triangle arrangements working, I'll make a continuation post.
Let me finish up here by saying that there's no reason we couldn't layer these triangular sections, either! Perhaps we go over each hex, rolling one set of triangles to determine the layout of its natural resources, and another set to determine its high-level inhabitants and their holdings, and another to determine if this hex has any particularly awe-inspiring natural areas -- perhaps there's an XP bonus for visiting them, and spending a day appreciating the environment. And then of course there's the whole business of using civilization/wilderness patterns to determine salient features: inns, quarries, monasteries, royal hunting grounds, ponds, cliffs, crossroads, bridges, fairgrounds, signposts, ravines ...
Sunday, July 10, 2016
My World, Part 3
And for another milestone: as of right now I have reached 99 recipes in my system, an increase of 25 from the listing given in this blog's very first post. See if you can spot all the new items on the table (fewer than 25 new ones, since some of the 25 are undisplayed "partial goods.") Several still need tweaking, and some need serious tweaking, but for now I have numbers I can work with.
Now that I've shown the latest version of the price table output, I'll take a few steps back and return to where I was last time with explaining the pipeline of programs which build up to this table itself. Today's agenda is the imports and pricing calculator, which proceeds in several steps.
- Since I have access to a list of all the types of resources and services which are available in my world, we first loop through all of the towns listed in ** Town Info**. If a town doesn't have a given service or material, we set the count for it equal to 0. This step is done purely for programming purposes, not because it represents anything special in the pricing algorithm. If I didn't do this "zeroing out" before anything else, I'd have to have repetitive code later in the file to check each town's info storage to check whether a given resource is present. This way, I can just assume that every town has an entry for every resource.
- I copy the Town Info items into a dictionary called Original Town Info. These will be kept so that I can refer ot the original values, since I will be updating the values in the Town Info dictionary in-place during the import step. While doing this, in order to save a step, I also calculate the original global totals for all materials. This is saved in the variable originalWorldResourceCounts (ought to be called ...materialCounts, but this code was written before I'd realized I wanted to reserve the word "resource" to refer to both "material" and "service." Oh well. One day I might change it, but it's in no way a priority.)
- We do some definitions which will be needed later. First, by dividing world production into originalWorldResourceCounts for each resource, we get the size of each reference of that resource in "concrete" units -- pounds, ounces, cubic feet, and so on. This is one thing we need to find the price of, say, a pound of iron ore.
- I don't think it's come up before, but: anywhere you see the Decimal() constructor function, just read it as the number which is parenthesized. Decimal() is a tool for representing decimal and fraction numbers exactly, without being subject to minute errors which arise when working with the basic decimal representation of numbers in Python and most other programming languages. I use numbers wrapped in Decimal() in order to preserve accuracy in my calculations, much like significant figures in chemistry equations.
- Finally, note that I don't have units for services. I don't yet have a need to figure out exactly how many people 1 reference to "blacksmith" represents. Perhaps some future upgrade will require this.
- I have labelled on the graph the distance between each town, and the resources each one has.
- Here is how importing to town A works:
- Let's begin with the products at town B, which is 2 units of grain. The distance from A to B is given here as 3. We add one to this distance: otherwise, in the case of a distance of 1 such as exists between B and C, then the exact same amount which is available at B would be available at C, and vice versa. That is to be avoided: we want travel distance to reduce the movement of goods.
- So: having added 1 to the distance of 3 to get 4, we then divide the 2 units of grain originally at B by this 4, and get 0.5. I emphasize "originally" because we do not want to be basing calculation of goods imported from A to B on a figure which includes that which B has already imported! Otherwise we'd be double-dipping: import to B based on A, then import to A from B based on figures which take A's import to B into account, then we could import to B from A and the figure goes up again ... it doesn't make sense. You could do it, but it wouldn't make any sense. There is one round of imports, only, and the amount to import from each place is always determined by the references it ORIGINALLY had, before anywhere did any importing from anywhere else.
- Thus, in Town Info (NOT in Original Town Info), we increase A's references to grain by 0.5. The higher that number goes, the cheaper grain will end up being at town A, since it represents more availability.
- OK! Partway done for town A. Importing from town C to town A is just the same procedure. The distance from A to C is 5, so our divisor will be 6. C has 1 reference each for sugarcane and copper ore, so A will import 1/6 of a reference for each of those. We add those fractions to Town Info for A. We are now done with importing for town A. Its final reference counts are: (1+1/6) or 7/6 copper ore; 1/6 sugarcane; 0.5 grain. Remember that by using Decimal(), I don't have to worry about calculating fractions like 7/6 by hand, or worrying about repeating decimals numbers like 1/6.
- We repeat this procedure for each town, importing from all other towns. Thus the number of import operations performed is N * (N-1): for each of N towns, we import to it from all of the (N-1) other towns.
- The algorithm here proceeds in two parts:
- For a resource R at town T, take the ratio of T's references of R to world total references for R, and divide the base value of a reference into that ratio to get the price per reference for R at T. The higher T's references to something are, the closer the ratio is to 1, and thus the lower that price per reference is.
- Then, divide that base price by the size of the reference, and store this value as the cost for a single "smallest unit" (1 lb, 1 oz, whatever) of the resource R.
- Let's do an example: let's arbitrarily fix the value of a reference at 1000 gold pieces (GP). Continuing the example above, the references to copper ore at town A are (7/6), and the world total references to copper PRE-IMPORT were 2. Thus the ratio is (7/6)/2 = ~0.583; we divide 1000 GP by this number to get ~1,714.286 GP. This is the base price per reference of copper, at town A.
- Then, assuming that the size of a copper ore reference is 2000 pounds, we divide again: ~1,714.286 GP / 2000 = ~0.857 GP per pound of copper ore.
- And there you have it! We now have a starting place for any recipe which works with copper ore; or the price paid to the assayer, if the players want to buy copper ore for some purpose or other.
Wednesday, July 6, 2016
The Ultimate Form
Now unfortunately with present computing technology, or even with that of the likely future, we can't get anywhere even close to what I've described. But I submit that if the few and dedicated among us work hard with what we have today, ever working to computerize sections of our game rules, and use the computer to create and power bigger and better D&D tools, then after another 40 years of this hobby maybe we'll finally be close to what is supreme: near-infinitely customizable worlds with all kinds of software knobs for the DM to tweak in order to create a high-fidelity game environment of almost any design.
Note that the above does not in any way signify or glorify some kind of transformation of D&D into a videogame! The two arts are distinct. D&D (the type of game) is still D&D even if computers are fundamental to its being played. We consider it completely normal today to do record-keeping on a computer, to draw maps on a computer, to roll dice on a computer, or even to have a virtual game table on the computer. Yet I think it's accurate to say people get cold feet when one proposes to make computer use mandatory for playing the game. Why? Imagine the benefits: storing auto-updated, always-clean, formula-incorporating character sheets; automatically and painlessly tracking character encumbrance, ammunition, and spell uses; providing easy hyperlinked or pop-up lookup for spells, special attacks, damage dice ... hell, all that lookup suggestion requires is a good website. No hard work at all if your rules are primarily typed up on the PC.
This is why I am posting about how I do the game. This is why I will continue to talk about my methods, and show off my tools.
I'm looking forward to 21st-century D&D.
Do you use the computer while actively DMing sessions?
Do you use it to make things for D&D, outside of the time you spend running sessions?
Have you programmed any rules into an automatic form (to any level of detail, even if it's just a toy diceroller?)
My World, Part 2
Today I'll finish talking about roads, then give a brief overview of the environmental data I'm using in my world, and how it's generated.
So: roads. As I said before, I leave the calculation of the specific hexes in each road up to the shortest-path program I wrote. But there's no reason I couldn't manually specify some or all elements of this process. I could manually determine each hex in each road, or manually determine some of them and then leave the rest to the computer. Furthermore, I have a way to calculate distance based on number of hexes traveled and elevation differences between each pair of hexes, but if I didn't have that, I could certainly manually specify a road's distance as well. One day, when I've got Earth data in an appropriate format for plugging into this system as a replacement for Town Info and part of World Generator, I'll be forced to start manually specifying roads if I want to maintain a minimum level of correspondence with reality.
Now: I've mentioned World Generator a few times. This program's name stems from my original efforts to generate a world with regions, resources, city placement, etc. all specified semi-randomly on top of a Perlin noise elevation-generation system. Obviously I am doing manual city and resource placement at this time; however, I have retained, for the time being, the noise-generated elevation, as well as accompanying code which specifies the following:
- the elevation cutoff which determines whether a hex is land or water
- spreading of moisture inland from bodies of water
- temperature (roughly speaking: very cold at the pole, very hot at the equator, with intermediate values representing areas with season-dependent or otherwise variable temperature ranges)
- climate (based on a slight simplification of the Koppen classification, currently taking moisture and temperature into account, but not elevation -- which could always be added in, in order to properly capture e.g. the boreal forest climate type)
Thus, an approximation of one hemisphere of a planet is laid out in the large, with bodies of water, rainforests, tundra, savannah, desert, steppes, and so on. The area map I showed in the previous part of this series is located near the bottom-right corner of the hemisphere. Since we're looking at the hemisphere from above, "west" and "east" can only be defined relative to some point on the map. "North" means toward the center of the hemisphere, and "south" means toward the edge, the equator.
(To avoid using "north" to mean "up" (toward the physical top of the map), and so on, in my code I use the abbreviations UL/UP/UR and DL/DN/DR to refer to directions relative to the physical map instead of the above gameworld-internal concepts of "north," etc. These abbreviations mean up-left, up ("top"), up-right, down-left, down ("bottom"), and down-right: the six hexagonal directions.)
OK, that's roads and an overview of the relevant portions of the World Generator. The plan for next time is to talk about resource imports and pricing, and then I'll dig into the final stack of fiddly bits, which is the construction of recipes: the formulas which determine just what each object is made of. Placement of resources and services is important, but in my mind, the recipes are the goal of this system. The trade table(s) is the end product, the final result of my hard work.
And by the way: I'm at 93 recipes now, up from 74 in my first post a few days ago. I'll refrain from posting a new version for a bit. Maybe at 100 or 110 or 125 I'll post it again.
If you have any questions or comments, please post away! It's so encouraging to see people respond to what I've done, even if you're just giving a heads up that you're reading.
Monday, July 4, 2016
My World, Part 1
Let me walk you through what these tools I keep talking about look like, and how my world works at this time. In this series I'll take you through all the pieces of the system that culminate in the price table you saw in this post. You'll learn how the systems that I have made currently function. Once again, I'll stress that the price table, and this infrastructure which builds it, is all inspired by Alexis over at the Tao of D&D. The map tool, which I'll get to in due time, is all me. It was originally the idea of a system which would be able to output data for both a map tool and a trade table which inspired me to begin work. I think it has been a fruitful journey so far.
Here's a diagram giving an overview of all the main chunks of the system. We flow from data about towns and resource production into calculations that give prices for each resource, at each town, and then calculate the cost of goods based on those resources and on the availability of services. This much I touched on in the pricing post, linked above.
Today I'll introduce you to Town Info. This file (which is written in Python but acts more like a database than a standalone program) contains data on each of the towns in my little fantasy environment: namely, the raw materials which are produced there, and the artisan industries which that town is known for. I usually call the former "resources" or "materials," and the latter "services." If you've read Alexis's description on his system, take note that at this time, all my towns are considered "markets;" thus, the players can buy the full selection of goods at each place. This is simply because my world is not as detailed as I'd like it to be -- but I consider D&D to be a lifelong project, so I am not worried about this or that area not having enough detail. One day I will get to everything.
So what are these numbers next to each resource and service? Those are the count (in abstract units called "references") of how much each thing is produced or otherwise available for use at that town. We'll return to these later. For now, let's talk about the end section of Town Info, which looks like this:
addConnection is a helper function that simply records the fact that a road links the two cities in question. You can check for yourself against the map above, and confirm that all the mentioned roads exist.
What is notably absent from this section is the question of which hexes a road passes through. This is especially important because passing between hexes with significantly different elevation requires extra travel time. Here's how I do it: within the World Generator stage listed above, I've programmed the computer to find road details for me. Given a connection between two towns (as recorded by addConnection), the program in question will find the shortest path between them, while taking the travel increase for elevation into account. Then it records the hexes of that path into the road's data. This is why not all roads are straight lines: for example, going around a hex with much higher elevation might only cost 2 or 3 hexes of movement, but going through it might cost 6: 3 to move in and 3 to move out.
If I chose to, I could change the program so that the exact hexes a road passes through could be manually specified. Or I could choose to change what the cutoffs are for differences in elevation between two hexes which increase travel time.
That's all I'll get to today, as it is the 4th of July.
Friday, July 1, 2016
On the Ball
One of the things I'm working on is my own version of the knowledge skill (or "sage" skill) system which Alexis has invented for his game. In short, sage skills are a way of quantifying knowledge about the game world and giving it over to the players as CERTAINTIES, things which they are guaranteed to know and which they can act on.
Why? Because it expands the range of playstyles players can use. Because it suggests new avenues of action, new reasons to explore, newly-useable items or novel purposes for ones that have become old hat. Things opening up and unlocking. Giving the players certain areas of guaranteed knowledge also pins down what the game world is like: if your druid knows X and Y about mushrooms, then he knows it, full stop, and it's the truth. This is part of the process by which the human world, with its enormous complexity, is broken down into appropriately-sized chunks and reified as part of the grand edifice that is D&D.
I want to present here some thoughts on the assassin and thief class, since Alexis hasn't touched on those yet (he's been focused on the cleric and druid, with occasional forays into other classes.)
Here are some of the ideas in my file:
First off, there are the classic thief skills, plus the assassin's poisoning and disguising abilities. I don't intend to touch the thief skills since in my game they're mostly not exclusively "thief" skills anymore -- it's just that the thief gets bonuses on them. The exceptions are Open Locks and Pick Pockets, which are pretty much thief- and assassin-only (save a lucky result on the background* generator.)
Poisoning, however, could be lifted out and made into its own skill tree, or perhaps folded into Alchemy. Either way the assassin would get to start with a free talent in this area, giving the ability to use and recognize poisons but not yet make them.
Disguise could conceivably also be made one of the early choices in a more general Subterfuge discipline. This could include things like: throwing one's voice; imitating a specific kind of artisan or religious authority; fooling lie detection (even spells? I dunno); and telling if someone is telling the truth, lying, or just plain IGNORANT (i.e. is incapable of truth or lying because they don't know the matter themself.)
Well then, on to the wholly-new stuff. I think that the thief is the class focused on "following the money," while the assassin is focused on knowing how to dispose of people by learning everything there is about them. This suggests both types of character would have abilities related to reconnaissance.
- Know affiliation: figure out what local factions or groups someone is affiliated with by studying how they treat and react to others. If they don't have any loyalties, perhaps they can be swayed to yours ...
- Telling if someone is keeping a secret or hiding information.
- Guessing someone's emotions from subtle cues, without needing any overt display.
- Predicting someone's reaction to seeing the party, or to seeing one of the members -- in effect, getting to read the reaction die in advance, and try to compensate for it. Perhaps I would also have to include a single suggestion for something to improve or alter -- or offer as a gift, bringing me to:
- Guess gift. You want to know the right amount to give the watchman to pay him off? You need to know just what type of wine the mayor likes? Got somebody to poison and don't know what food they're gonna go for at the reception after the lecture? Ask an assassin.
- Eavesdropping: quite useful. Would have to do better than the old Hear Noise rules for this, though.
- Intuit room purpose: after a period of observation, figure out what a room is used for, based on who goes in and out, what they're carrying/using, what sounds you hear, and so on. Anyone else might be able to conjecture, but the assassin/thief will know FOR SURE. If you haven't got one in the party, time to hire one ...
- Intuit room layout: lets you know beforehand where guards, (potted plants, walkways, entrances and exits ...) ought to be placed in a room which you've studied with Intuit Room Purpose. A bit videogamey? Maybe. But I think it could be cool. It's not as if you could use it unlimited times, or whenever you want.
Some of these lend themselves more to the assassin than to both, since I've been thinking mainly about that class. Here's one or two thiefy things:
- Geographic knowledge about where things come from. Get boots on the ground and spend a week investigating, then ask a certain number of questions along the lines of: what's the biggest iron-mining town in this country? What's the best place to go within 100 miles to sell some bolts of linen? My trade system will let me judge those things pretty easily. And, once I've upgraded my map program, I might even be able to print off a local map with color-coding for item production. Wouldn't that be cool? Imagine the thief swaggering up to the others: "I've done some research and if we want to get rid of this
- Fixer: you've made a contact in the local black market who can make problems go away, guaranteed. Just gotta be able to pay his price -- but the first one's free. Whatcha gonna call him in on? This is a good one because when confronted with a precious expendable resource, players will usually only use it up grudgingly.
- Who's who around here? Spend time investigating and you'll find out who's in charge of the churches, the politics, the manors, the guilds. Spend even more time, and you'll start gaining info on who's REALLY behind this, that, and the other thing. (This one would be good for the assassin, too.)
Bring Your Own Bucket
But that's a little too much like the college classes which required one to sit through a tour of the syllabus on the first day. So forget that: let's dive into content.
Three weeks ago, I reached a milestone on one of my D&D projects: the economic system. That milestone was the first successful end-to-end calculation, from town and geography info all the way through to getting the price a player pays for a particular product, based on its local availability and the local availability of the kind of artisan which makes that product.
Three weeks ago, all my trade table had for each city was pig iron, the humble first step on the way to steel.
Now? Take a look:
The price that the players pay for each item on this list is the result of calculations (which I call a recipe) which specify the amount of raw materials it is made out of, and the type of artisan which makes the item. In some cases one recipe is made from another; an obvious example is that the leather pouch contains leather (tanned cowhide) as one of its ingredients.
Not all items are shown here, either: this is only finished items, which total about 50. The "74 recipes" claim at the bottom of the second picture is including partial goods; I hide those because the focus is on the things players usually want (although of course I can un-hide them.)
The key is that since each raw material and each type of artisan (or more generally, service) varies in availability from town to town, the price of each and every item will vary as the party travels.
Want to outfit your army of two hundred with swords? Get yourself to a place where iron is plentiful, because it's the primary component in the steel for those swords.
This type of system gives players a reason to go to a particular place. It also creates a source of differentiation for each town, as I can draw on the goods produced there to give an idea of what its culture is like. Most importantly, this system broadens the array of behaviors which are suitable "moves" for playing D&D. Want to be a merchant? This system supports that. Want to exercise your character's background skill in being a blacksmith or a fisherman? Go right ahead: take those fish right to the fishmonger and sell them. Or maybe you're of a more destructive bent and want to try for some industrial sabotage ... in that case, rest assured I'll update the system to reflect the chaos you've caused, so you can take advantage of the cheap prices you've engineered.
Obviously I don't have everything I want yet. I have few foods, and almost no armor and weapons. Both of those are very important. Plus I'd love to have things like furniture, and wages for men-at-arms or servants, and clothing of all kinds, and I've been meaning to throw in the calculation for rope, and oh, got to have backpacks, and I can't forget about containers (buckets, vials, sacks, flasks) to hold liquids and such. Right now, milk is BYOBucket.
So there's plenty to do. But 70-odd items is a good start.
(Credit where it's due: my economic system is based on the principles given by Alexis Smolensk over at Tao of D&D. If you haven't read him, consider it your lucky day.)