I've got a confession to make: I've started playing Unangband.
This is a big step for me. Usually I last about 2-3 minutes, come up with an irritating bug / user interface issue that isn't quite right, and dive back into the code for hours at a time.
But this time its different: I'm enjoying playing, even if I have the feeling the game is a bit difficult at the moment. The initial reason why is that most of the obvious bugs are fixed, whilst I have enough scary and hard to debug ones to worry about. But I'm also really enjoying the variety and 'feel' of the game at the moment: its possible to quickly get into lots of interesting situations that force me (and hopefully you, the player) to have to think about what to do.
For instance, I've run into seemingly impossible odds, pushed my luck to get out and almost made it. All the monsters I've fought have been interesting and provided a challenge, particularly with the priest characters I've been playing. I've spent what would have been a dull time 'worm farming' Clear Mushroom Patches, which remained on a knife edge of difficulty, despite gaining 4 levels in the process, and then used the left behind spores to kill one of the uniques who proved my undoing in the screen shot earlier.
But at the same time, when the difficulty level is so finely balanced, you tend to look very hard at the decisions and lack of choice that you get in the early phase of the game. These low level lessons are all about making everything useful in some manner.
For instance, priests in Angband and variants don't get to choose their spells from a prayer book: the gods grant them randomly. So I've had to tweak the 1st level spells so that all the starting spells are good choices in some situation, regardless of which one is granted. Remove Fear is (mostly) a useless spell for an Unangband priest when few monsters cast fear so early: by boosting it to a Benediction, which combines removal of fear, some other light status effect reduction, and a one-turn massive AC boost, its now a viable spell to cast while cornered, even if its just to buy you one turn.
I'm going through the starting mage spells with a fine-tooth comb as well: at the moment, mages start with one spell book with almost 20 spells in it, most of which are offensive. While I really like the selection of spells, offensively, its too good, because a mage is quickly able to find the resistance hole in a monster and exploit it. I was hoping for more of a mage having to run from certain monsters because they haven't got the right attack counter.
In addition, some spells, like Wizard Lock or Infravision, which can help a starting mage defensively, are a waste of time compared to the wide variety of attack spells available, or other defensive equivalents, like Phase Door. So I'm considering breaking the mage starting spellbook into 4 different books, each with a more focused selection of spells in it. And I'm concentrating on adding alternatives to the defensive and miscellaneous spells this time round. There'll be Shadowstep, which works like Phase Door, but only in areas of darkness, Purify Self, Blood Binding, and Ignore Pain which are alternatives to Cure Light Wounds and others.
Hopefully the trade off in slots caused by the additional books will make casters focus a little more on magic in one area.
Thursday, 31 May 2007
I've got a confession to make: I've started playing Unangband.
Thursday, 17 May 2007
I enjoy reading Gamasutra, although I don't necessarily agree with everything written there. However, this article has a lot to say about the level design that I'm trying to achieve, particularly with reference to monster hierachies.
I don't necessarily think the author conceived of constructing ecologies through procedural generation, however, the same techniques apply.
Tuesday, 15 May 2007
Just an aside, can I direct anyone who designs games, particularly multiplayer games to read everything written by David Sirlin at sirlin.net, and then buy his book?
I don't buy game-design books, but I bought his.
Monday, 14 May 2007
One thing I'm constantly looking for is different ways of killing. I'm in the process of implementing an improved 'cause of death' mode for high score tables following an entertaining killed by an open floor death dump on the angband.oook.cz ladder. So you can rest assured in the next release you can die of 'undercooking a white jelly', 'sniffing a Red Mushroom patch spore' and 'shooting yourself in the foot' (I'll leave the circumstances of each death for your discovery).
But much more interesting than dying, is how to kill the enemy. Since its not often clear what the drawbacks are, here's a quick summary of the options in Unangband, the enemies that they're good against, and the drawbacks. Anything with a (?) I haven't implemented yet.
Here's a table showing the methods and advantages and disadvantages of each that should help you make this decision. There's a lot of methods.
If you're reading this from future to past, can I suggest you start with part one of this article. Part two is here.
I was originally going to write an article about ways of giving warriors more defensive options. But that's not what I'm going to do. What I'm writing instead about is how to give warriors more incentives to keep killing stuff.
Angband is a dangerous game, where line of sight and line of fire are critical ways of 'managing monsters'. Your best choice is inevitably standing around a corner, with only one, or two monsters able to strike at you, or even better, carving out a diagonal corridor, so that even monsters capable of area effect spells can only get a bead on one grid adjacent to you. The methods of escape and 'resets' are all about getting from a dangerous point in line of sight to a lot of monsters, to a place where out of their view, either by creating obstacles around you (create doors, earthquake, destruction) or teleporting yourself away. And speaking of teleportation, its much safer to do it to them, instead of yourself.
Which is why I don't want warriors doing any of that.
I want warriors to advance into the fray, get as many enemies in line of sight, brutally melee them to death with impunity and quickly recover when they do get hit.
I've already suggested some ways of advancing towards the enemy, by dodging from side to side. You can do the same thing with blocking as I've described it, by allowing blocking to last two turns (And that's why I do this blog, because I only realised that as I write it), and alternating standing still (e.g. blocking) with stepping.
But when you get into contact with the enemy, how can you improve the situation?
Well, for a start, your enemies should be usable for as well as against you. They already block line of fire for a lot of attacks, such as arrows and bolts. While Unangband and other variants based on 4GAI no longer have the 'keystone Kops' situation of monsters shooting each other in the back, having monsters near you is great cover for directed attacks, they'll take damage from area effect attacks used against you, and they'll prevent more dangerous monsters being summoned in the area they occupy.
I'm considering treating every attack as a dodge towards the enemy you're fighting. That means whilst you're attacking someone, ranged attacks used against you are have a chance of hitting the person you attack.
I'd like to implement a 'push past' monster move, to allow you to switch positions with an enemy. Its easy enough to overload the 'run' command for this, and dodging would also apply. There should always be situations where running between the legs of a dragon should make sense.
Then there's the overall 'confusion of melee'. It'd make sense to have ranged attacks have a lower chance of being used against you, the more enemies are in your direct vicinity. A 10% reduction in chance for each enemy greater than 2 within 2 grids feels about right, but that's just off the top of my head. So if you're completely surrounded by 8 monsters, you'll likely be safe from attacks at range.
Those should help indirectly, particularly the confusion of melee. But playtesting will tell me whether these are enough.
I suspect I'll have to add some 'attack meter' that builds up as you do damage in melee, and rewards you with extra blows directed at targets other than your primary opponent. It'd be good to have the attack meter allow recovery of 'some' hit points: resting with the attack meter would reset it, but heal you. Making this apply with healing would give me the chance to let monsters heal you to reduce your attack meter - counter-intuitive, but I'm sure there'd be situations where this made sense.
Is that enough?
I'm an addict, but I'm really picky about what I read - just found a great sf book review site that I'll be trawling through shortly.
Nothing to do with roguelike game development, until I write that sf crashed on an alien planet roguelike I've always wanted to (that's right after the end-of-millennium pre-apocalypse real time strategy game I'm also working on).
One of the great things with the borg in Angband is that you spend a great amount of time staring at what amounts to a screen saver. I mean, its seriously addictive.
But its also a great diagnostics tool, because it automates the checking of a lot of code paths - which is why even if the variant of Angband you're developing is too complicated, you can grab Leon Marrick's dumbborg and see if the code you've written crashes or infinitely loops. I'm using it at the moment to try to help diagnose up a weird object corruption bug, where an object gets stacked on itself, and breaks all the object list traversal code horribly. I don't particularly feel like manually generating thousands of item drops under 'real conditions', and the borg is quite happy to run around killing monsters, or at least zapping them while completely immune to damage.
It was during these diagnostic runs that I noticed in the monster display list: 76 Tyrants of Hell. Now, a Tyrant of Hell is a deep summoning demon, that likes to summon other demons. And having 76 in line of sight is probably not a good thing, in fact, it looks suspiciously like a bug of some kind.
Rogue-likes have a tradition of what is known as 'chain summoning', where a monster summons a monster which has summoning spells, which then summons a monster which has summoning spells and so on. Its usually associated with demons, in fact IIRC, its possible to die from 'Too many demons' on a level in some early ancestral roguelike.
'Chain summoning', when it occurs, is probably at the point where you want to get off the level. Your ability to do damage will be exceeded by the rate at which new monsters are appearing, and you'll be quickly overwhelmed. I say quickly, because unlike monsters that breed explosively, chain summoners tend to be quite tough.
And running the borg in Unangband, I was seeing chain summoning a lot. In fact, a couple of monsters (Tyrants of Hell, Beholder Hive-mothers) dominated this.
Some analysis of why this was happening was in order, and I quickly found the culprit. In Unangband, the monsters are restricted to only appear in a narrow band of levels. In Angband, they can appear on any level from (close to) their native depth onwards.
What was happening, as a result, is that its highly likely that the monster a Tyrant of Hell summons, is another Tyrant of Hell. In fact, its so likely, that they may as well just breed explosively, except by spawning more than one copy of themselves at each turn. This is reinforced by another piece of code in Unangband called ecologies which restricts the total different types of races on a level, but the problem is still there without it.
Which is not what I wanted at all.
So I've added some code, to enforce 'strict summoning' under some instances. 'Strict summoning' basically states, that if a monster can summon itself, then the monster will only summon weaker races than itself instead. This means the summoning chain will go in one direction, so I can guarantee a Tyrant of Hell will summon some kind of lesser demon, and that will summon a lesser demon and so on, ad infinitum.
However, its still not good enough. Because we are summoning summoners, the rate of growth is still exponential. With summoning in Unangband being permitted out of sight, the only restricting factor is monster mana. And the rate of monster mana regeneration over a large number of summoners is such that enough mana will be generated per turn to allow additional summoning. This lowers the curve, but still permits it to grow exponentially.
Since the only monsters I want growing exponentially is breeders, I've got to come up with some other strategy. And any strategy that I choose, I have to be able to cull very quickly summoning from the list of monster spells very cheaply, because monster AI is a frequently called routine.
I've got a couple of options:
1. Total monster population limits.
Total monster population limits means that when a fixed number of monsters of a race has been created on a level, that's it. No more are generated. The two problems with it are: I don't want population limits for breeders, and I'd have to check the list after each monster death, and flag whether or not anything is left alive that is a candidate for each summoning spell.
Allies is where a monster can only summon a total number of allies, and no more. When a monster is summoned, the allies are shared between the summoner and the summoned, plus a small increment (most of their friends are common to each other). The problem is: killing one of the monsters should add allies to others nearby.
I'm probably going to go with the first one: I can work around the breeding limits by limiting total summons only, not total population. And while I like the concept of allies, I don't think the behaviour is as interesting. And conceptually, the allies pool for a level is the total summons limit.
What should result is monsters who summon from a large range of different allies, and then restrict their summons to allies they haven't yet called on. I might even recycle existing monsters, and allow summons in the instance where the 'summon pool' is exhausted to instead teleport far away monsters nearby that qualify.
Tuesday, 8 May 2007
This is nothing to do with the book - I just like the turn of phrase.
I've taken a little time out from Unangband development, but am now back in the thick of it, which is where I am having my proverbial cuppa. And reflecting on where I am at, I can say assuredly: 'Don't mess with Angband level generation'.
I mean, I know the code inside and out, I've 'hardened' the code, in the style of NPPAngband, so that it gracefully aborts from many potential infinite loops. I've improved the tunnel generation code so that it actually checks connectivity between all rooms instead of just hoping for it. I've added lots of terrain, different room types, monster ecologies, room contents based on the description of the room, theming of levels, room decorations and more, which work really well together.
And yet I'm still not happy with it, and can't tell you definitively whether any change I intend will work or break the code.
This is the soul-destroying part.
Level generation isn't clean code. Its lots of 'tried and true' heuristics to try and connect funny shaped bits into an interesting topology. I refer you to a great paper on procedural terrain generation (pdf) in the game Tribal Trouble that attempts to emulate erosion using a number of 'real world' algorithms as a part of their level generation. The solution: thermal erosion doesn't work quite right using the physically correct model, but hey, if you reverse the sign on the key equation, it looks much better. So lets use it.
I've got quite strong ideas about what constitutes a level, as least as far as Angband goes. It should be a topology of 'interesting' and 'uninteresting' rooms with 'good' connections (and some 'bad' connections), and contain a 'theme' that a player can choose either play in or bypass.
All 'interesting' rooms should have 'good' connections, so that the player never has to cheat to get between them. 'Uninteresting' rooms can have 'bad' connections: these are primarily so that monsters can navigate between them. A 'bad' connection could be hard to navigate for the player (e.g. filled with lava). The 'interesting' rooms should be ranked in terms of increasing 'interesting-ness', with equivalent escalating threat levels. The 'most' interesting room on a level may be 'badly' connected though. It contains the best reward, and should be a challenge to get to.
The 'theme' is usually a set list of monsters, plus some 'themed' rewards. Because we have an infinite pool of levels to pick from, players should be able to pick and choose from this pool relatively easily (by moving to another level if required).
So this implies a starting area with a number of staircases leading from it: a partial ordering of rooms away from the starting area, a vault or some other reward location that potentially hard to get to, and a ranking of monsters from easy to hard within a level.
Of course, Angband's level generation gives none of this.
And how does Unangband's level generation shape up?
1. We place the hardest room first, because its usually the biggest and hardest to place. Of course, that means it'll get in the way of any attempt at partial ordering, because statistically, the big, hard room will be in the middle of the level.
2. Connecting rooms is hard. Real hard. Its the likeliest reason for infinite loops. And I get these even just ensuring all randomly placed rooms are connected. Forget trying to connect them in any order.
3. If we can't connect the rooms in any order, its sure hard to figure out where to place the starting room, or to generate monsters in increasing level of difficulty.
4. I've got this great system of room descriptions to hint what the toughest monster on the level is. But its based on monster attributes (drops potions = laboratories, fires arrows = rooms filled with broken arrows), that don't actually tell the player what the monster is: except for leaving dead bodies or statues of the monster around which (may) tell the player exactly what it is. So the player usually runs into the monster, before having enough information to be helpful. And if I don't add a little bit of noise, it makes the levels look really boring. But that just makes the even limited information about the monster too unreliable...
Ah well. Writing this has given me ideas. But none of them are elegant - they're all just variations of hacks. And I don't have any guarantees that they'll work.