At work, someone wondered aloud what had happened to the dancing hamster. I'll tell you what happened: months locked in a caged. Now he's back.
The dancing hamster, ronin, bereft of master, master only of the dancing hamster fu. None have seen the technique and lived.
This weekend's project was to write a program to generate tiles for maps in Tale. To this end, I needed to extract clips of trees, mountains, and mushrooms from svg files like tree-poplar.svg, that include layers with "metadata" like crop boxes and "pathing" boxes. Pathing boxes are rectangles that represent the base of a 3d object, so the umbra of a tree, for example. The idea is that these trees, mountains, and mushrooms can be combined into terrain tiles by filling a space with their pathing boxes, then rendering the corresponding terrain features from back to front. So, this weekend, I wrote a tool that will at length fill a region with randomly selected terrain features pared out of a given "plate" of images. Here's the resulting mushroom forest.
The algorithm is quite slow; it has an order of complexity something like (shooting from the hip here) O(n2). First, I extract the clips from the SVG plate, including their pathing and crop boxes. I populate a list with the sizes of each of the pathing boxes. The bulk of the algorithm is taking a given region and filling it up with as many of those pathing boxes possible in a suitably random fashion. To this end, I keep a queue of "regions" these boxes can occupy. These regions can overlap. I seed the queue with a single, large region. Then, I iteratively pull a region from the queue at random, find a suitable pathing box at random, place the pathing box inside the region, and then test every region in the queue against that pathing box, breaking any region that overlaps the pathing box into smaller regions that do not overlap the pathing box. Crawling through numerous off by one errors and infinite loops that still vex me though they're fixed, I finally managed to reliably plant a region with pathing boxes. I then sorted the pathing boxes from back to front and composited the grand image from the corresponding clips.
The next task is to set this up so that tiles can be generated incrementally throughout the world, and speed up the performance by using a quadtree, presumably the same quadtree we'll be using to distribute nodes of the world across multiple servers and organize the rooms into a hierarchical geographic grid.
The other major task is reviewing the mushroom graphic for ways to make the end result prettier. Perhaps thinner, pastel borders, and maybe some parametric color variation, or shadows.
I'm beginning to regret having not blogged my daily progress for the last seven years. There are a lot of undocumented discussions and ideas for Tale. One of the more recent ones is the notion of shards of hexforce. I've enlisted the aid of Geoff Kriston (previously mentioned by his mmearth.net character name, Toronsire Elenath) and he's distilled this description of the shards:
The Hexforce is the mystical mover of magic, the essence "mana", in Tale. Shattered into six shards, these pieces and their shadows are both mana dipoles and tomes of instruction, inscribed with instruction in the fundamental mechanics of the Tale world.
I wasn't planning to make horse graphics for Tale. In face, I was decidedly planning to avoid making horse graphics. This isn't so much malice toward the "ooh, pretty horses" crowd, but a conscious decision to make the world as odd and ridiculous as possible. Well, in order to construct a certain pun, I needed the accoutrements of a horse. So, now we have horses. I've also added some layers for aquatic mounts. I've also, as promised, begun testing and integrating the rider into the mount graphics. Here are samples.
So, the sorting rules for the sprite graphic (which includes such lovely permutations as the Pachyrat, Bunnysaur, and Llamacorn (do you ever get tired of writing L's? I think not)) were getting unwieldy and as a result were largely incorrect. However, I was having some trouble convincing my topo sort algorithm to report cycles, and even then it would have been problematic to figure out where they needed to be broken. What does this mean? Vaguely, it means that my rules would occasionally say that the bunny ears were in front of the bunny rider, and occasionally the bunny ears would be behind the bunny rider. Of course it would be much more complicated. Here's an example cycle: the bunny ears are behind the mount head which is behind the llama fur, which is behind the saddle, which is behind the dinosaur head, which is behind the bunny ears. Since the rules file uses a lot of regular expressions and sandwiching techniques, these cycles are hard to find. I needed a way to visualize the problem.
Enter Graphviz. Graphviz is a tool that takes data describing a graph and produces an image of the graph. A picture is worth a thousand words. I spruced up the Cixar Python library's graphkit module (which uses Graphviz) and wrote a tool that produces graphs of layer sorting rules files. This is what I beheld. (old rules)
So, there are a few cycles in there. Ok, maybe a lot. They're easiest to spot by looking for arrows pointing up instead of down. Ooops. Clearly this isn't manageable. So, I started rewriting the layer sorting rules one set of layers at a time. I added a feature that lets me make "virtual layers" like "rider_face_bottom" and "rider_face_top" so I could organize the layers into boxes and sandwich the boxes. This is the result. In addition, the layer rules are all correct now, and I will be able to show off some demo graphics that include the mount rider tomorrow. (new rules)
I bend a lot of ears, especially at work, about the Tale project, and some novel ideas come out of these conversations. I do not wish to implicate the innocent, so I'll spare the burden of names, for now. One thing led to another. It started with gathering ideas for siege weapons, like alternate names for "Trebuchet". Out of that conversation came the idea of a ballista ballista ballista, which would send monkeys into orbit. Some felt that this was too ridiculous, so we came up with the idea to "warm up" our audience by starting simple: Signal Monkeys. It's not so absurd a notion. Once we've gotten you accustomed to the idea that well trained monkeys with signal mirrors, telescopes, and semaphores might reliably relay data on enemy positions for ballista artillery fire, we introduce weather monkeys (monkeys hanging from weather balloons), and then the Ballista Ballista: a long range ballista that fires a monkey and a crossbow into enemy territory. From there it's a small step to accepting the notion of a Ballista Ballista Ballista, equipped to send a signal monkey into geosynchronous orbit with a paper cup and a lot of dental floss. This evening I synced up with my partner in crime:
Ryan: EVIL MONKEYS
Kris: oh, there are plans. let me tell you.
Kris: signal monkeys
Kris: monkeys with crossbows on backs of ballistae. weather monkeys. spy monkeys. kamikaze monkeys. you name, we've got it.
Kris: if it couldn't get better, penguins with clubs, penguins with rockets, penguin submersible re-con, penguins launching penguins, kamikaze penguins. you name it, we've got it.
Kris: oh, it gets better.
Kris: PANDAS! pandas riding pandas, pandas with rifles, panda blimps, sniper pandas, pandas with wire guided missiles. you name it we've got it.
Kris: it gets better.
Kris: sub-nautical mounts. sea-rats, otters with gills, elephants with snorkels, plesiosaurs with snorkels, you name it, we've got it.
Kris: ironically, ducks will not be seafaring
Kris: they have good union representation
Again, using the recently created svg-atomize and the sprite merge script, I threw together additional layers for a plesiosaur.
Tale, like all well designed programs, has no design. You probably wouldn't be able to tell if you looked at the code, but when it comes down to it, it is what it is, and that's the only explanation for how it got to be that way. On the flip side, you probably could easily tell that the program has no design because it also doesn't have a release date. This, I know, is a dubious design philosophy, but I like surprises and emergences.
I was quite surprised to find that Tale was turning out to have a lot in common with a card game, in the sense that the artwork would be static, and effects would be applied by stacking and transforming graphics. This would be analogous to blood and poison counters, "tapping" and discarding. I find this both convenient (as a developer with limited resources) and endearing.
Today, I drafted three effects for the game. One of which is the blood counter graphic. It's a 20 layer image with sets of blood splatters that Tale will liberally apply as a creature takes damage. I imagine that you won't have a chance to heal during combat, but you will be able to apply bandages. With any luck, this will stop the bleeding until you have a chance to rest. I also drew up a posion cloud and spore cloud. The graphics are shown on the EffectList on the Tale wiki.
A couple days ago I was charged by Ryan Paul to produce a graphic for a llamacorn. Since then, it has become an eagerly anticipated phenomenon, with a teething crowd of at least three awaiting its release. Several celestial bodies had to arrange themselves to make its debut possible, but at last, I give you the llamacorn. Technical details follow.
In the vein that I loosed with svg-sort, svg-filter and the hitherto unmentioned svg-select, I postponed creation of the llamacorn until I had svg-cat. What does it do? svg-cat is a tool for "concatonating" SVG files, such that the layers of each successively supplied SVG file stack to form a unified image. This is analogous to the command line tool cat which concatonates a list of files and renders them to standard output. Now armed with a complete suite of SVG command line manipulation tools, I wrote two scripts for working with the now unwieldy sprite.svg: anomize and merge. atomize takes the sprite.svg file and creates an individual SVG file for each layer, a la svg-select and svg-layers. merge takes these layer files, sorts them with the sprite topological sort rules, and reconstitutes them into a single graphic, a la svg-cat. This enables efficient augmentation and editing of the sprite graphic, because now I can pare out the layers that I want to work with (for example, heads if I want to add wigs), add the layers I want, atomize that graphic, then merge, and buildall. Now I don't have to do tedious manual sorting or tedious manual hiding of irrelevant layers. Also, I can now do spot checks of numerous layer configurations by automatically generating graphics from the newly constructed master image and making sure that the layer sorting rules are doing their job correctly. All of these scripts are in the Tale repository in https://cixar.com/svns/tale/bin and https://cixar.com/svns/tale/art/sprite.
In the process of developing this utility, I spent 90% of my time hunting and killing a single bug, propagated by Inkscape. Inkscape decided that it wouldn't render randomly selected cells if the loaded file was saved by a previous version of Inkscape, which hadn't the courtesy of adding an inkscape:version attribute to the SVG file. This problem had to be fixed in a text editor (gvim) since Inkscape wouldn't migrate the file properly. Furthermore, the problem had to be found by a binary search by selective replacement between a "corrected" and "flawed" version of the same graphic. I think I might file a bug report.
Today I fleshed out some more graphics for vehicles and rides. In particular, I applied the same filtering mechanism that I used for mallards to produce some graphics for various permutations of the rodent mount from the general purpose sprite graphic. After I got that done, I moved on to constructing some graphics for land vehicles like SiegePlatypus, TrojanBadger, SteamCastle.
For the last couple weeks, I've been working on artwork for Tale, the MUD, you know. That is, two weekends ago, I got back from visiting the family down south and had an itch to make something, so I've spent all of my off-time since scratching my brain and mouse-pad with fervor. The first thing I drew was a multi-layer sea and sky vessel graphic, the Mallard. The Mallard is one of the seminal concepts for Tale, a Norse style galley with steam and blimp upgrades. It's the focal point for blending a mediaeval theme with a fantasy theme with a Victorian sci-fi (steam-punk) theme. I finished it, cranked out some permutations, called it amazing, and moved on. Since then, I've populated a wiki with bunches of monsters, items, and game design memes.
Today's project was to finish writing the automation for generating permuations (sail plans) of the Mallard. To that end I did a bunch of technial stuff. Skip to the next paragraph if you don't care about technical stuff. The mallard graphic proper is a single SVG file with something like 120 layers. These layers include such wonders as "mizzen-top-gallant-yard", "bow-jib-outer-sail", and "sweeps". Constructing a mallard graphic is a two step process replete with danger. The first step is to filter the graphic for the desired layers. I've constructed several layers files which include all of the necessary layers for a particular sail plan. The second process is sorting those layers to preserve the three dimensional illusion. To this end, I have several sets of "rules" for sorting the layers, rules like "the yard arm is behind the mast", employed exhaustively and brutally. There's one set of common rules, one set of rules for ships that appear to be sailing away from the observer, and one for vessels that appear to be sailing toward the observer. Using these rules, I construct a "digraph", merely a set of layer names associated with layers that are known to be behind them, and then perform a "topological sort" on those layers. I do this all with the command line, so constructing boat-100.png looks like: cat mallard.svg | svg-filter boat.layers | svg-sort rules boat.rules | rsvg -w 100 - boat-100.png. That process applied iteratively renders our 29 (so far) selected sail plans. I can't wait to play a game where these vessels are set in bitter competition and players scramble to arrange their sails to catch the wind and their prey or their daring escape.
So, here, in all their glory, selected permutations of a mallard.