Showing posts with label rant. Show all posts
Showing posts with label rant. Show all posts

Tuesday, 14 February 2012

Dense Bugs

"The reasons go back to perhaps the most important empirical result in software engineering, one we've cited before: the defect density of code, bugs per hundred lines, tends to be a constant independent of implementation language. More lines of code means more bugs, and debugging is the most expensive and time-consuming part of development." — Eric Steven Raymond, The Art of Unix Programming.

I rather dislike verbosity in code, so I would love the above quotation to be true. Unfortunately at the moment I'm running on received wisdom and gut feeling; I have yet to find any concrete studies on the subject. It certainly wouldn't be easy to perform such a study, given the moving target of popular languages, frequently poor distribution of languages in a given domain, differing fluency of programmers requiring large sample sizes, choice of how one enumerates bugs and when one chooses to do so... I'd hope that a language that makes high-coverage automated testing easier would have a somewhat sharper decline in extant bugs over time, but maybe that's simply wishful thinking.

There are limits to how far this pursuit of brevity can be taken, of course. The more conceptually dense the code the more wetware involved in expanding it to a form that can be understood, and humans are hardly infallible when it comes to such transformations. Misunderstanding an obfuscated chunk of code will lead to the introduction of bugs, and the point at which pleasantly concise turns into impenetrably terse will be different for each reader. Meaningful naming of intermediate values helps me unpack a series of functional transformations of a collection, so I'll fairly regularly expand a series of maps, filters and folds within a let expression, and if necessary interject comments (with small functional chunks of code producing values bound to meaningful names, it is rarely necessary). So far so standard.

On the flipside, various kinds of boilerplate that add nothing meaningful beside additional LOC are all too common, even when avoidable. To take a small example, as the quite lovely Effective Scala notes, there is little benefit to "syntactical ceremony" (I love that phrase) by way of superfluous braces on simple functions or control structures. Yet many languages do not allow for such details to be elided, and even if they do we have a curious tendency to enforce maximal syntactic salt. I have never yet worked at a game developer whose coding standards allowed the quite standard C++ convention of skipping the braces on single-line conditionals and loops.

I call bullshit on this kind of ruling. In fact, I am not at all convinced by coding standards beyond a way to record naming conventions, formatting of comments to generate valid automatic documentation, and very general guidelines for style where the choice might otherwise be non-obvious (e.g. avoid using interfaces for small data-structure objects used in an inner loop, those vtable jumps add up quickly). When it boils down to the dictation of salting levels, especially favouring more rather than less, such documents cease to be useful.

In my opinion, anyway. I'm sure someone disagrees, because the bloody things never cease to be a pain in the neck.

Long story short, death to large codebases and coding standards that promote them, no matter how small the increment.



Game progress ticks along, I'm currently investigating dual quaternion skinning and fiddling with the relationship between the game logic loop and the renderable representation of logical entities. In particular, it was deeply confusing having multiple monsters performing multiple actions all at once, so I've fallen back on the model used by Wizardry 8 (among other games): wait for animations to complete before letting the next logical entity take a turn. I am worried that this will become painful for large groups of monsters, so this will doubtless require iteration.

I'm also going to have to check how to better push animation state onto renderable entities. At the moment it's just inferring that a "hurt" animation needs to play because the entity has less health than it had last turn, and so on. This is simple and makes sense in some cases, but does preclude having a "stagger backwards from explosion" animation that is unique from a "walk backwards carefully" animation, for example.

Thursday, 2 February 2012

Fragile Worlds

Why do certain programmers - myself included - keep returning to procedural content generation in games?

It's so easy to get it wrong. Too homogeneous, too random, too formulaic... humans seem to be wired for pattern recognition, and most procedural content consists of layered patterns. Even worse, it sometimes gets used in games where we perceive a narrative bent, games where there is an overarching reason why the world is the way it is... but the why of such generators is always 'because Perlin' (or whatever). We can layer procedural details over a narrative world, but unless they remain harmless, forgettable greebles attached to the background or strictly bounded by the requirements of the story, the tension between that story and random numbers can irritate.

I think we've also gotten used to a small army of architects and landscape designers marching just ahead of our progress through game worlds, artfully arranging every detail where it matters and gently eliding where it does not. The generators do not care. They may produce breathtaking scenes, as nature is wont to do, but equally produce a hodgepodge of clutter and boring expanse. Worse, they might have the audacity to produce these at exactly the wrong time, leading us away from the golden path through the game. The horror, not only do we have choice in where to go rather than marching through a linear series of cutscenes and set-piece battles, we might not even have a flashing neon marker to follow when we wish to rejoin the railroad plot!

So that's why we shouldn't use them, except as a time-saver for little, tedious details that an artist or designer would be wasted upon.

Except.

What such generation produces, at least to a good approximation, is a unique world. As mentioned, the massively chaotic systems of the real world are quite capable of creating something inspiring, terrifying, engaging, and explorable. We're aware on some levels that this world is all we've got, for the span we get to walk upon it. Whether this remains true, for now I think that the worlds which are unique and fragile resonate the most with us.

Roguelikes get brought up often in discussions concerning PCG, along with the hazy nimbus of somewhat similar games. These are important not just because they operate at a level of detail which we're happy to accept procedural content, where we're free to elaborate upon it internally (of course all these corridors aren't alike! They're just rendered with the same ASCII characters, despite being replete with details and variations that conveniently use no disk space or polygon budget), but also because of the permadeath mechanic. It makes everything so much more interesting if you know that not only are you breaking new ground, but that something wonderful might be around the very next corner that you never, ever get to see because you just died to a pitfall trap. And along with your character, the world is gone. The new one will be broadly similar of course, but you'll never find out what was around that corner. Instead, you get a universe of fresh new corners, that you might die before you have the chance to peek around them.

Unless you savescum. We don't discuss such perverse habits in polite company.



This rant dates from sometime in the middle of last year, when I was exceptionally bitter about some linear game or other. Skyrim has once again struck this nerve, at once hurling me into a wide open world (woo!) and poorly designed (if very, very pretty) linear dungeons (boo!). Many games do offer very compelling procedural worlds, roguelikes not least of them. Minecraft and Terraria leap to mind as in addition to a large and potentially interesting random world, they offer huge player agency in effecting changes to those worlds. It's a potent mix.

So, this is maybe a tad angrier than I feel is appropriate right now, but it was mostly complete. And I still feel strongly that fragile gaming experiences, unique procedural worlds and the divisive permadeath mechanic all have their places.

Wednesday, 1 February 2012

Success With Leiningen, Kinda

Getting Leiningen working was a bit of a trial:
  1. Download lein.bat!
  2. Note that it can self-install, but only if wget or curl are to hand. I'm currently trying to get it working under windows, my primary gaming and dev environment, so I go with the manual download option. Progress seems good.
  3. Putting the .jar file in the place where lein is installed (and on the path) doesn't work. Harrumph a bit.
  4. Mess with batch file a bit, including directing Leiningen at Clojure.
  5. Give up, download a windows implementation of curl, add to path.
  6. >lein self-install now works! Hooray! And oooh, the .jar file goes in \self-install. Durr.
  7. Leiningen crashes on attempting to do anything, with a huge Java call stack. Pout.
  8. Notice that in my arrogance and delusion, I have pointed Leiningen at Clojure 1.3.0, the newly installed latest version, but the original wanted to use 1.2.1. Download the older version, alter batch file again.
  9. Yay, I can make a project!
  10. I'll want to use lwjgl at the very least with this at some point. Some research points me at swannodette's lovely native-deps addition to the tool, and the existence of lwjgl-clj at clojars.org. Cool.
  11. OK, I have a zip file for native-deps. How do I thrust this in lein's general direction?
  12. Welp, via adding it to :dev-dependencies in my project.clj file, it seems. I guess I'll keep the .zip file in case of emergencies. Or something.
  13. Argh, version 1.0.0 just blows up lein again.
  14. Phew, 1.0.5 works. I can now grab lwjgl-clj through the magic of... magic, I guess. And curl possibly.
  15. Look at it go, downloading all those lwjgl-clj files!
  16. I've got a little text-based thing that'd make a nicely self-contained test project for leiningen. Let's try turning it into a self-executable .jar
  17. >lein jar: and there was much grinding and gnashing of gears.
  18. Class "hexed" was not found.
  19. Oh, :gen-class! Silly me.
  20. Class "hexed" was not found.
  21. Err... oh, -main.
  22. Class "hexed" was not found.
  23. wat.


And there were some more steps, mostly consisting of my own stupidity fighting with my own stubbornness, before finally:
>lein uberjar
>java -jar hexrl-1.0.0-SNAPSHOT-standalone.jar
SUCCESS!




Woohoo!

Now, I list my failures mostly because I am quite stupid, and I hope other people feel better about themselves as a result. But also because there's a fair amount of assumed knowledge concerning most JVM languages and their associated tools. Before I started working with Scala, I had only the most vague inklings regarding the black magic of .class and .jar files. Ant, maven and all related stuff is... well, initially I was curious and tried to learn more. Now I'm just hoping most of it dies and gets replaced by something. Anything. As long as it doesn't involve XML.

I still find it vaguely offensive that I'm expected to this.like.project.my.structure, preferably including URLs (hah), but in moderation it works well enough. Knowing that you need to generate an appropriate class exposing the correct form of a main method is reasonable. It would be nice if some of these things failed more gracefully in case of version mismatch

Long story short, now I have achieved a critical point: using a cuddly-ish tool to build a working application, however trivial. Chances are therefore good that I will learn to use Leiningen correctly (somewhat) and frequently.

Edit: I promised pretty screenshots, and have not yet delivered. The next step is apply the power of the ant-agonistic build tool to the OpenGL-using framework, check everything works with the version of lwjgl available at clojars.org, and then see what happens. Hopefully there will be relatively few explosions and couple of simple meshes to screenshot.

Friday, 4 July 2008

Sub-textures


I apologise for the lack of lighting, but as I haven't gotten around to making the normal map equivalents it seemed best. This is just a simple way to add extra variation to the dungeon, by doing a crazy version of texture splatting basically lifted wholesale from here (the post on the 10th April, can't find a direct link to the appropriate post).

At the moment, the blend weightings (violent primary colours above) are simply normalised fBm output, but adding in some stuff based on local environment should give far nicer results... some moss growth around water, for example, and sand/mud under the water level. Anyway, these are used to control the placement of four textures (other half of the above image). You can see the red corresponds to my original ground texture, green is a mossy muddy thing, and blue is some dry earth stuff. I'll hopefully get a better picture with normal maps and generally nicer textures up soon.

To diverge into a rant briefly, OpenGL support under Vista (ugly ugly ugly Vista) is shocking, at least for my nasty Intel chipset. To add insult to injury, there's no tex2Dgrad equivalent under GLSL even on my shiny desktop hardware, which will make some of my planned shaders a complete PITA to implement. So expect to see fewer pretty screenshots and more waxing lyrical about things like dungeon generation in the near future...

Right, I'm off to a weekend of Dwarf Fortress and beer.

Monday, 18 February 2008

Attributes - background waffle

Via the wise ramblings of the Rampant Coyote, I came across this interesting discourse on attributes in (C)RPGs.

This got me thinking about things. Sloooowly of course, because I'm dumb, but thinking regardless. One thing I'm keen to experiment with is making all attributes useful in some fashion, and all combinations of skills and attributes, well, as far from stupid as possible.

So here's a long, rambling pile of waffle loosely related to attributes. Especially how they should work in a single player, single character, combat-heavy, turn based, randomly generated RPG. What can I say, I have specific needs.


Attributes: What the hell are they anyway?
Attributes in most CRPGs suffer from being a terribly mixed abstraction.

On the one hand, they represent basic inputs to the game mechanics. For the average test, most games seem to favor some variant of skill+attribute(s)+dice roll. Sometimes the size of the dice depend on the attribute rather than it being explicitly present, sometimes the skill isn't really a skill, and in d20 you mangle the attribute pointlessly to generate some half-arsed bonus from it rather than simply using the damn thing as-is. But in any case, it has an often visible and direct influence on the result of tests.

But on the other hand, they often have an altogether more narrative and character-driven role. They're named for qualities we value, and can readily identify in the heroes we hope the character will join. Strength, dexterity, agility, intelligence, perception, wit, endurance... even pure jammy luck.

This tends a cause a big mangled mess, because these attributes are so obviously tied to feats in the real world that they end up assigned to associated tests in-game. Of course, these are rarely distributed evenly. The vast majority of important actions a character might take will end up clustered like freezing penguins around a scant few attributes, leaving the remainder in the cruel katabatic chill of 'dump stat' status.

Once the narrative and mechanical concerns get tangled, it's fairly tricky to sort out. Picking attributes based on game mechanics is transparent and easy (or at least easier) to balance, but can feel clinical, dull, devoid of depth and flavour. Picking attributes that resonate with our heroic fantasies frequently creates a mish-mash of derived, secondary and tertiary attributes, and great swathes of illogical or poorly distributed actions. It becomes hard to reason about which choices are quantitatively better than others, both for the designer and the player. Strange caps and level dependencies are introduced in an attempt to duct-tape the whole thing into working order. WoW presents an excellent example of this kind of system gone completely bonkers.

So, are there any games or systems that got it right in this regard? Only a few come to mind.
  • SPECIAL from the Fallout games seemed remarkably close. It was quite hard to find dump stats for any character, to me a good indication that the attributes have been well-used. Not bad, really. You were granted some leeway by the secondary characters you acquired, though.
  • Guild Wars used purely mechanical attributes, and went further than most by making them profession specific. Add to this the ability to freely change attributes between combat areas, and the whole package worked rather well. Unfortunately all the campaigns hit the level cap fairly quickly, so beyond your initial choice of primary profession and the short ramp up to max level, there's really little in the way of permanent character development. To be fair, this wasn't and isn't the focus of the game, but it makes it hard to evaluate the effect of such an attribute system in the context of a more traditional RPG.
  • Games which deviate strongly from human baseline can often use a more abstract, artificial system. Even though I hope they all explode from shame, a few White Wolf products make a fair job at this. Sometimes. The dot thingy still blows chunks, but anyway. The assumption here is that the character's can do pretty much anything a human could even remotely expect to accomplish, so the only attributes of interest are those involved with strongly superhuman qualities. This puts them safely outside the terrible reach of 'common sense', and therefore they're subject to being fiddled until they work within the game, without even giving the illusion of modeling the real world.
  • If my brain worked, this would be a longer list.


The archetype that doesn't fly
There's an issue that rolls around in RPGs, and that's how infrequently the agile, fast guy is a wise choice compared to the big slow bruiser. This kind of contrast is a staple in fiction, but it rarely works out sensibly in games, at least in part because of the way attributes commonly work.

I did originally have an enormous spiel about my beliefs regarding why this so often doesn't work, but the upshot was mostly to do with timing so I'll save it for a later post.

With respect to attributes, this is probably just a very pointed example of how a narrative influence doesn't even necessarily support key clichés in the kind of stories they often want to tell.


Snut makes a considerable effort to get back on-topic
Pondering on the issues of chained actions. We think of some things in RPGs as being discrete events, such as a single attack. But what really happens often boils down to at least two tests. One to see if we hit the target, and another to see if we affect it. Sometimes this latter is more about magnitude than a simple all-or-nothing, but over time the result is much the same. Sometimes the first test influences the second, such as a critical hit in a d20-based system, but they're still rather distinct.

This presents an interesting knot, because often attributes will influence both tests. A large bonus to either end of the sequence is of less use than medium-sized bonuses (boni? Nah) at both testing points. Combat-based tests may have additional effects too. Does a poisoned blade do anything if you don't overcome the target's soak? What about a magical flame effect? If you miss the initial to-hit type roll, is there a chance of hitting another nearby target?

Going back to an earlier point, attributes which influence both ends of the equation frequently become overpowered. Strength in d20 is an incorrigible repeat offender in this regard.

As I've no desire to puzzle through the convolution of a two-attribute curve by some peculiar random number distribution, it seems to make sense to combine these two steps somehow. A wonderful game (The Secret of Zir'An) presents one option for doing that, although by itself it translates poorly to a roguelike implementation. In a nutshell, an attack is an opposed test as we're all used to, but every point the attacker beats the defender by is available to spend on various combat effects. At the most simple these allow for increased damage or armour penetration, but they scale to include all manner of fun options, disarming opponents or blinding them, trips, throws and generally being evil.

Zir'An still has a (flat) base damage for weapons, mind. Taken to the logical extreme, where damage is entirely dictated by the level of success, this kind of simplification might exacerbate some problems with combat munchkinism. In most current games even if your foe's basically guaranteed to hit you every time, you can still hope for minimal damage, and in fact the 'death by a thousand cuts' routine rather mandates accuracy and damage be distinct.


Implementation? Maybe?
A few things that have been decided about this game (still unnamed, I need to fix that) which could help in designing an interesting and workable attribute and skill system:

  1. I'm drawing a clear and inviolate line between mental and physical attributes. This is a fairly obvious result of the nature of the player character. I'm also thinking that attribute increases through level advancement (or whatever) will alternate between these two subsets.
  2. It's a roguelike. Or roguelikelike. It's all about survival, combat, traps, treasure, random stuff and inevitable, bloody death. In addition to being an inhuman soul-sucking immaterial monster, there's no real reason to be good at making chit-chat with the meatlings anyway, as they're only there to be killed or point you to the next dungeon. And maybe sell you some overpriced tat. Hell, there may not even be non-hostiles for several game iterations! So social attributes and skills can bugger off, and I don't need to worry about trying to make them less dump-statish.
  3. There will be no humans. Even the creatures not inhabited by servitors of the uncaring gods won't need to be realistic in the slightest in their stat block, because the comparison with humans will be speculative at best.

Of course, there's also cloud lurking in this argent glow:

  1. Monsters, especially intelligent NPCs, must be easily auto-levelled by the game - including attribute increases. Random generation should also be possible. As far as I can tell at this stage, this will boil down to making attributes as evenly spread as possible. I place no great faith in the ability of my monster generation code, or the fairness of the RNG, so it's quite likely that really broken statblocks will come wobbling into view. They don't have to be equally dangerous, of course, but the more evenly spread everything is the less work the AI will have to do to at least make them interesting, if not effective.