Tuesday 30 December 2008

Programming Wars (not)

Sometimes miracles do happen. A recent thread on r.g.r.d. asked for advice on programming languages to use for developing roguelikes. And the corresponding thread didn't descend into a language war. Is the roguelike community finally growing up?

Sunday 21 December 2008

Bad Dungeon Design

Apologies for the lack of updates recently, this has gotten in the way.

There has been a bit of a hooplah recently over a new Dungeon Generation algorithm released into the public domain over on r.g.r.d. and touched tangentially upon over at ASCII Dreams. Here is a sample of its output:


I'm of the opinion that this is sub-optimal for roguelikes, primarily because of one main factor: geometrically, it is too deadly for any reasonable player. Leaving aside the obvious irony of this statement since roguelikes are a genre where one mistake in game-play could kill you forever, a map such as this tilts the balance of the game too far away from the RNG towards a style of game-play where the presence of even one OOD monster with extended following abilities means the level (and almost certainly) the character is a certain and complete and unavoidable write-off. A map such as this, lacking any in-level escape options, would almost inevitably lead to an overwhelming sense of frustration quite quickly, and would shortly result in whatever game used this dungeon design being deleted off the players' hard drive.

So what could be done to make this map more suitable? Not that hard actually (though I may be underestimating the difficulty due to not being familiar with the original algorithm). Each "branch" needs to be connected up with another (not just through the centre) to allow at least one alternative escape option for a player:


If this is done, I feel this could be another interesting dungeon design, one of many that roguelike authors could use.

Thursday 30 October 2008

Hiatus

Development of Kharne is in hiatus at the moment, despite my exams being over and life conditions ideal for coding. This is mainly due to a mistake of my own volition. I opened up Delphi recently to do some coding and was greeted by the following screen:


All standard and custom VCL components are missing and all settings have been reset back to not just default, but a pretty much empty configuration that is no good for anything except console apps. The packages (both standard and custom) are all gone as well and are unreinstallable. In short, my installation is totally corrupt. I think I caused this by partially uninstalling Delphi by accident whilst doing a major clean-up on the hard disc a while back. I’ve tried reinstalling Delphi but despite hacking about in the registry I can’t get any custom components reinstalled.

There’s an old urban myth going about that the Chinese word for “crisis” is a conglomeration of the symbols for “danger” and “opportunity”. So I think I’m going to take this opportunity, when funds permit, to upgrade my development environment to Delphi 2009:

Once I do that, development will restart at full throttle. In the meantime, I hope to be more active than recently on various aspects of roguelike programming.

Friday 19 September 2008

Delays and Delays and Delays...

Yes, I'm aware I was meant to have released a version of Kharne by now. Unfortunately, real life has intervened quite dramatically over the last weeks/months. I have exams coming up in early October and once those are over, I hope to get back finally to development, Wrath of the Lich King not withstanding. I'll also release what I have coded so far at that point (although many things will still be incomplete of course, but such apparently is the life of a Roguelike).

In other RL news, its good to see Lords of Dark Hall is now back in active development. And a new (even harder, I suppose) version of Crawl (I'm still playing and dying in 0.3.4). And I also notice that LambdaRogue which only recently achieved the magical 1.0 status, is currently being rewritten. From personal experience, I can tell you that this rewriting business is a dangerous two-edged sword. As I recounted before, when I tried this for the original version of Kharne, it depressed me so much it stopped me writing any code for about five years.

And of course, where would roguelike development be without a flamewar (surprisingly not on r.g.r.d. this time). wouldn't be the same place without a major flamewar. On rec.games.roguelike.misc this time. Over permadeath, inevitably. Years and years ago, I would probably have agreed with the posters who (rudely) advocated not using permadeath. But now, let's just keep things, and especially Crawl, the way it is, ok? That's what makes it Crawl.

Friday 8 August 2008

Design Decisions and their Consequences

Back in the days of 8-bit computing, a popular genre of computer game was the text adventure. My formative years in computing was based around them, and to this day, one of my favourite computer games of all time is Heroes of Karn:



Despite the limited (and often downright annoying) parser, to this day, this game has an atomphere and an ambiance that is unsurpassed.

But one of the ironic things about this game is that in one particular area, this 1983 game is more advanced than Kharne is, some 25 years later. And its because of a design decision I made a long time ago, back when I first was programming Kharne.

I'm talking about the ability to have multiple items in the same location:


In Kharne, I have discovered I cannot do this, without extensive modification of the code, because the Dungeon object represents items currently located on in the Dungeon (e.g. on the floor) by a single 2D array of integers:

Objects: array [1..DUNGEONSIZEX, 1..DUNGEONSIZEY] of integer;

Of course, representing objects in the dungeon this way has advantages - it is dirt simple to program and is extremely quick - but it disallows more than one item per square (it still allows a single stack of items, such as 19 arrows for example, as stacked items in Kharne are merely an instance of a single item with a "count" attribute).

Now, it wouldn't be horrendously hard to refactor item code to allow multiple items per square - indeed the Roguelike Dev FAQ at Roguebasin mentions the standard method of doing this:

"...For the list of items, use a linked list. This allows many items to exist on the same tile. Store a pointer to the beginning of the list. The pointer takes up 4 bytes of memory...."

Leaving aside the gratuitous Unix/C-ism ("the pointer takes up 4 bytes of memory...") . implementing a linked list would probably be trivial.

So why am I holding off from doing this? Why do I think that, for now, I'm better off with only one item per square?

There are four reasons I can quite quickly think of:

Firstly, consistency. Now, yes, roguelikes aren't noted for consistency - for example, dragons ("D") take up the same amount of space in game as a rat ("r"), and arguments for and against consistency on r.g.r.d. are notorious for producing much more heat than light. But there is something especially jarring about having a rat take up the same space as three swords, four maces, two sets of armour, four goblin corpses, and a kitchen sink.

Secondly, at the moment, Kharne levels are not persistent. They will be eventually (to a limited degree), but when you do not have persistent levels, then there is no point in stashing. Stashing is a powerful argument for multi-item storage.

Thirdly, its something else to worry about - another obstacle to getting the game out. Already, this rewrite of Kharne has turned into something much more extensive than I'd ever imagined - but its more of a marathon (in the sense of a journey) than a sprint.

Fourthly: how often in a RL (leaving aside stashing, obviously) do you actually need to stack items? When does it become tactically necessary, nay, critical to do so?

Your thoughts are welcome on this.

Incidentally, if you try and pick up the money, the Barrowight prevents you. The solution to the this dilemma is to "ATTACK BARROWIGHT WITH CROSS":


Obviously the cross is a thinly-disguised Mace of Disruption. Handy that. Much too powerful to put into a roguelike, obviously.



Sunday 3 August 2008

Here we go again....

Well, after the little break I've had due to RL issues, I've restarted serious coding on Kharne again. Look out for more information soon. Rather embarrassingly, I've just realised that there was no Drop Item functionality in the Inventory screen, so I'm currently implementing that. Data entry and framework coding for Monsters is on hold until I get the Drop functionality finished.

On a slightly different note, there's a new thread on r.g.r.d. entitled 'Is "identify" really good for the game?', which does as it says on the tin. I'm sure this has been discussed in the history of Roguelikes many times, and I think I'm in the camp that says, overall, that the ID-minigame is indeed good for the game as a whole. It is however, a real bitch to code, when you're working with non-primitive item data structures, as I am.

In other Roguelike news, Mario Donick has released v1.0 of his roguelike, Lambda Rogue. Its a rather splendid game, and even more splendidly, is written in Free Pascal, which is fairly compatible with Delphi. Mario and I both use the Recursive Shadowcasting Algorithm to generate FOVs, and I think I speak for us both when we say we're very happy with it. Congratulations on your achievement, Mario!

Monday 28 July 2008

Apologies #2

Once again, due to RL issues taking longer to resolve than anticipated (specifically the mother of all assignments on these beasties*), I've not done much coding or design work on Kharne since my last post.

However, in the meantime, a lengthy entire outline of an abandoned roguelike was posted on r.g.r.d., and judging from its length, I can see why it was abandoned. When confronted with a todo list of that magnitude, any programmer, no matter how great they are at getting things done, or how skilled, would shake and quail.

For Kharne, I have a multitude of ideas, enough to keep me programming for two years, yet the basic framework, or what passes currently for the basic framework is already 14k lines of code:


But unlike the author of the abandoned attempt, programming on Kharne will recommence soon.

* Incidentally, as far as Wikipedia goes, the article isn't too bad. It does underestimate the impact of viscosity however, and doesn't mention hot-spots or boundary layers, but I'm not going to go to the lengths of editing the article to show this - I prefer to spend my time coding instead!

Friday 11 July 2008

Apologies

Apologies for the lack of posting recently. I have been very busy in that strange place called Real Life. I hope to have more progress updates and to resume posting in the next few days.

Thursday 12 June 2008

Stealing Ideas from other sources...

One of the most ironic things I find about writing a Roguelike game is that the ideas for additional content never seem to stop bubbling to the surface. And that, when analysed, most of these ideas come from either other RLs, CRPGs or (especially) MMORPGs.

For example, instead of coding, I've been playing (and dying mainly) a lot of Sangband recently, and I've realised that the lack of character classes is an inspired design choice. Much has been written about classes in Roguelikes, and eventually, perhaps, I will also want to take Kharne into a classless direction. Classes are, on one hand, convenient labels/stereotypes for a character and on the other, a restrictive straightjacket preventing the character from achieving his or her true worth.

Another idea which I think might prove to add another facet to gameplay in Kharne is Reputation, which in a World of Warcraft context is:

You can gain or lose favor, otherwise known as Reputation, with many of the several different factions in Azeroth by completing certain quests or killing certain creatures. Doing so will usually unlock special rewards or new quests to accomplish.

My only concern with implementing reputation is that it can turn into a mascochistic grind very easily - there are majoring game-play balancing issues to be considered (much like Pudding Farming in fact), but a synergistic reputation system that minimises repetitiveness could add much to a RL.

Another idea, currently being discussed on r.g.r.d is that of Dungeon Morphing, dynamically changing the dungeon either independent of the player or as a response to the player's actions. Where I think this could be extremely interesting is implementing timed levels that require the player to do something in a certain period of time or else face near- or certain doom. Like in Oblivion for example.

Leaving all this side, on the development front, my current task is finishing the monster implementation, which I need to do before I can progress magic further. One of the decisions I made early in the design process has come back to bit me slightly. I've made great play (here on this blog and elsewhere) of the fact that our brave little @ is just another creature. But why does a rat, for example, need to receive the same treatment as our @ in terms of having an inventory and suchlike? And do rats really need to have Charisma stats as well as Armour and Evasion?

Thursday 5 June 2008

Progress Report #5

Slowly but surely, things are coming together. Here is a sneak preview of the new spellcasting screen:



For the sake of tradition, and ease of implementation, I've decided to forsake originality and go for the spell book approach found in many other roguelikes. There are fifteen possible schools of magic, grouped thematically, with eight spells in each. I'm also implementing basic metamagic feats, to allow a bit more flexibility with spellcasting.

In the above screenshot, our '@' has access to five schools of magic, and in the she can cast four spells from the Tome of Aether (air/wind flavoured spells) with varying degrees of probability of success and mana cost (which in turn are calculated from various stats and skills). Eventually, I hope to add some sort of miscast/mutation mechanism.

Current plans are to finish implementing at least the basic schools of magic, then start work on the monsters and serialisation. Then Kharne should see an official (v0.1) release.

Wednesday 4 June 2008

The Psychology of Getting Things Done

Andrew Doull over at ASCII Dreams has a screamingly relevant (to me) post up entitled The Cost of Interruption describing the travails that Roguelike Developers are going through. I must admit part of the reason I've slowed down coding on Kharne over the last couple of weeks is the same as his:

"...With coding, if I have a longer period of time, I'm more productive. Not as in twice as productive, but probably ten times or more...The reason for this is the time required to rebuild the mental model of the program before I can generate new, productive code. This mental model doesn't have to be complete, but it does have to be correct, and I've inadvertently introduced logic bugs that have persisted for years, due to faulty assumptions about how a particular section of code works..."

"...So rather than plain procrastination, blogging and gaming has become activities where I feel productive in a short term without experiencing this mind numbing interruption cost - the interruption cost of a blog entry is just re-reading the entry I've written so far, which is a much lower barrier."

I've experienced this succinctly in the last couple of days. Monday evening I was able to get a great deal of code written for the Magic-Handling GUI Interface in a good solid 2-hour stretch of coding, yet last night, when I finally managed to get round to doing some coding after spending most of the evening do something else (equally mentally draining as coding), I found I had great difficulty in doing even the simplest of functions (I was trying to write the routines to calculate the mana cost and spellcasting success probability of spells). In the end, I gave up and went to bed.

Its not quite got to the stage that Andrew describes though:

"...It has got so bad recently that I've started dreading coding, in so far as the idea of doing something half-way and getting interrupted is a feeling I don't particularly want to experience."

It also doesn't help that my s.o. is suffering from a bad flu at the moment and is thus spending most of her time playing Age of Conan, and seeing her play it nibbles slightly at the edges of my own MMO-addiction.


Thoughts on Serialisation

I'm finding out that implementing Serialisation (i.e. writing the state of the game out to disk) is a pain. Not only because pre .NET Delphi (I'm using Delphi 7) doesn't support inherent serialisation natively, in the way Java does, but because it requires a great deal of clarity of thought when it comes to designing and writing data structures and classes with serialisation in mind.

Let's look at what serialisation is required for Kharne:
  • Storing '@' information, such as current location, stats, inventory and current effects that he/she(/it) is subject to. The player is represented by a specific instance of the TCreature Class.
  • Storing the dungeon information. Ironically, I'm finding that this is the simplest to serialise, since the Dungeon class (cunningly called TDungeon) is basically just a multi-dimensional array of integers and booleans.
  • Storing the monster information. Monsters (also instances of the TCreature class) are stored in a TObjectList, and there are soft references to them in the dungeon class (by soft, I mean absolute ID addressing, not pointer referencing).
  • Storing the item information. Items are stored in a TObjectList, and there are soft references to them in the dungeon class. However, there is an added difficulty in that Items themselves are effectively compound objects (consisting of a base TItem and optionally one or more TItemEnchantment classes to represent magical properties of the item).
  • Storing the high-score table and any bones files.

The old Kharne did all this successfully enough, but with one major drawback: the save files lacked any soft of compression and were stupidly big (20 Mb!). This was due to the crude method I previously used for handling saves files (basically, standard Pascal WriteLn/ReadLn). This bloat is unacceptable however in the new Kharne. Fortunately, if I switch to using a more modern implementation, i.e. streaming (which Delphi supports extremely well using both TFileStream and TMemoryStream) and also use one of the many compression libraries, the save files can be reduced to an acceptible size.

Now, there are plug-in Delphi libraries available that implement serialisation but I'm not convinced that using them would be any easier than using the above methodology. I will have to do further investigation on these.

Wednesday 21 May 2008

Progress Report #4

Not that much has happened in the last few days on Kharne, progress wise, I've been busy doing other things in that strange place called Real Life. Most of the time that I've actually spent on Kharne I've spent refactoring some of the data handling routines to finish their conversion from flat-text storage to reading from the SQLite Database instead, but I'd like to present a little feature that I thought worked really well all the way back in TKAngband, and is pretty much an essential part of MMOs, and which I'm reproducing in Kharne. Ladies and Gentlemen, I present to you:





The minimap.
. Unlike the console version of Crawl*, for example, where you can't display the map and the dungeon view at the same time,



Kharne's minimap is in a separate window that can be displayed and hidden at will, dragged around the screen, and auto-updates as the player moves around the dungeon (always being centered on the player). I think its quite a cool feature, and I'm surprised more windowed-roguelikes don't implement it.

* Yes, I know Crawl's map offers additional functionality like traveling, but traveling is unlikely to be a feature of Kharne for some time. Incidentally, the tile version of Crawl does indeed have a minimap.

Monday 19 May 2008

Metaplots and Dungeons

All Roguelikes have metaplots, even if its only to give a thin veneer of reason as to why our little '@' hacks his (or her) way through dungeons. In Angband, the goal is obstensibly to defeat Morgoth. In Crawl, its to recover the Orb of Zot. In Nethack, its to recover and ascend with the Amulet of Yendor. Larn has an unusual plot device - the goal is for the player to traverse a dungeon in search of a potion that will cure his ailing daughter of 'dianthroritis'.

I haven't decided what the metaplot for Kharne will be yet, although I'm very interested in exploring different aspects of Roguelike gameplay during the different phases of the game. To this end, like Crawl, I'm going to implemente themed dungeon branches. Unlike Crawl however, I want all the different dungeon branches to be theoretically accessible from the town level (with one exception I'll come to later).

Each dungeon branch will consist of 10 levels, of increasing difficulty. There are 9 branches, therefore there are a maximum possible 90 levels to delve through.

Before describing each dungeon branch, there are a few important things I'd like to note about the intended gameplay:
  1. The challenge to the player should increase as he/she delves deeper. This isn't just a matter of throwing bigger and tougher monsters at the player (although this will happen), rather, I'd like to throw the player into progressively tougher and tougher situations. I have a few idea for implementing this other than some of the standard Roguelike fare, e.g. Vaults, Mutations and increased Monster AI.

  2. I want to avoid Angband-style grinding (e.g. the so-called "Stat-Gain" phase). It won't be necessary to visit every single dungeon or indeed every single dungeon branch - in fact doing so will increase the chances of a death since levels will be dangerous. Dungeons are semi-persistent - whilst within a dungeon branch, levels are persistent, but as soon as you leave the branch and return to town, they will disappear, Angband-style.

  3. I want to allow multiple paths through most of the game, to increase replayability. This would be as well as the standard roguelike randomness replayability. To achieve this end, all dungeons with the exception of the final ones are completely optional.

Player start out in the town level, called the Nexus:


The two introductory dungeons (suitable for levels 1 to 5), are The Wilderlands and The Fortress.


The Wilderlands is built using the cave-generation algorithm whereas the Keep uses the rooms-and-tunnels approach. The Wilderlands will be very much themed upon an outdoor feeling, with animal-themed foes, whereas the Fortress will have a martial setting and will be filled with goblinoids. It is intended that the player uses these two dungeons to learn the basics of Kharne's gameplay and to start the gearing-up process.

Beyond that, there are two intermediate dungeons (suitable for levels 6 to 10) - The Mausoleum and The Keep:



Both use the Rooms-and-Tunnels approach, and the Mausoleum is an undead-themed dungeon whereas the Keep is filled with magical artifacts and creatures. At the moment, I'm intending to have the first vaults appear in the later levels of these dungeons (although vaults aren't implemented at the moment), and the purpose of these are to equip the character with items that are necessary to venture further in a safe manner.

The Advanced Dungeons are suitable for levels 11 to 15 and are basically the Elemental Planes - the Planes of Air, Fire, Water and Earth:


At the end of each dungeon, on the bottom level, is a heavily guarded Elemental Key. This serves two purposes - one of these must be collected to allow the player to enter the final Dungeon (it doesn't matter which elemental plane it comes from), and also one will allow the player to resurrect once, with some....far-reaching consequences (I'll discuss this in more detail in a later post).

And then we have the endgame dungeon, suitable for levels 16 to 20, and the final part of the game. At the moment, its called the Abyss, and its filled with demons and devils and other similar creatures. There will be a macguffin at the bottom of this dungeon, the obtainment of which will be the game's victory condition.


Although the majority of foes in each dungeon will be specific to that dungeon and themed to fit in with that dungeon's theme, there will be a set of common foes across all non-Abyssal dungeons. Some of these will be in the form of demonic and elemental "invasions", with creatures scaled appropriately to the current dungeon difficultly (effectively these will operate as moving and non-permanent vaults). Other will be in the form of rival adventurers and adventuring parties. I'm especially looking forward immensely implementing these, as I remember fondly in Baldur's Gate the first time I came across a rival adventuring party.

Oh, and there will be one other special dungeon...which is specifically tied to player ressurection. I'm still working out the details, but to give you a bit of a hint, this is one of my favourite tabletop-RPGs of all time.

Sunday 18 May 2008

Language Wars

These last few days, I've been using some some C and C++ code from other Roguelikes as a source of inspiration for Kharne. Years ago, I used to work professionally in both C and C++, and to say I didn't miss them at all would not be inaccurate. However, looking at the Angband source code, I am experiencing not a small degree of deja-vu, and surprisingly, not all of it is bad.

Thers is no doubt that certainly C is still the most popular language for Roguelike development, and nowadays I would contend this is due to two main reasons: the strong cross-platform possibilities that it offers, and also the established momentum that such an exiting large codebase of already written (and finished!) Roguelikes can offer.

There's no doubt that C does have somethings right - I had forgotten how the increment operator was such a thing of beauty. Let's take this amusingly commented extract from the Angband source, specifically in generate.c:

/* Mega-Hack -- Paranoia -- prevent infinite loops */
if (main_loop_count++ > 2000) break;

The Object Pascal equivalent of this is much more laborious:

/* Mega-Hack -- Paranoia -- prevent infinite loops */
inc(loop_count); if (loop_count > 2000) then break;

Double the code, and nowhere near as elegant.

Parameter passing into subroutines is also not as elegant in Object Pascal as it as in C. There is a function used in tunnel building in Angband to find the correct direction between two points. It is defined and used as:

static
void correct_dir(int *rdir, int *cdir, int y1, int x1, int y2, int x2)
{
...
}

correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);

Now consider the Object Pascal equivalent:

procedure correct_dir(var rdir: Integer; var cdir: Integer; y1, x1, y2, x2: Integer); begin ... end; correct_dir(row_dir, col_dir, row1, col1, row2, col2);

In Object Pascal, I really miss the fact that you know straight away from the calling line which parameters are modifiable or not.

Even the use of { and } seems to be suddenly a lot less irritating than begin and end are.

This is not to say that I've become a sudden convert to Brian W. Kernighan's famous criticisms of Pascal or that I wish to rewrite Kharne from scratch in C/C++. Far from it. There are many things in C and C++ that are simply atrocious, and anyone proposing those features for a modern day language would be, and ought to be, shot. The oft-quoted string handling, for example. The ridiculous fragility of operations involving memory. And, dare I say it, pointers. And pretty much all of Kernighan's criticisms of Pascal are no longer valid when it comes to Object Pascal (though it is, I guess, slightly unfair of me to compare an effectively ancient language like C to a comparatively modern one like Object Pascal). For example, Object Pascal supports casting using the as operator, as whilst you cant quite turn apples into oranges as it sometimes seems you can do with C, as is functional enough.

Now, I think that I perhaps unfairly dissed C and C++ in the past, and with the incorporation of the standard template libary, C++ is certainly a fine development language, but I am still of the opinion that Object Pascal is better. As for C however, would argue that it is unsuitable for modern development - unless there are compelling reasons to do so - it lacks features that modern languages have by default (even C++ has some of these) - exception handling, many useful data types, function overloading and so on. But my biggest complaint about C is that it lets you shoot yourself in the foot too easily.

There are two caveats to this opinion though. The first one is that often opinions on programming languages are a function of familiarity. The second is that what is important with a programming language is how you use it to get things done. This may seem an ironic statement considering I've not released anything yet, but I find the combination of Object Pascal and Delphi allows me to implement things extremely quickly. If you're developing a roguelike, you may yourself have a different method of getting things done, but for me, I'll be sticking with Object Pascal and Delphi, although giving a richly deserved nod to C++ at least.

In other news, I've implemented a simple cave algorithm, with the following results:



Although the levels it generates are somewhat annoying to traverse, they do induce the claustrophobic and careful game play I want the Elemental Planes levels to feature (well, they will do when I add monsters!). All three types of dungeon mentioned in my last post are now implemented, although there's still a lot of refactoring to be done with the code.

Friday 16 May 2008

Progress Report '#3

I have a dilemma.

Currently Kharne could best be described as an interactive demo. I've posted screenshots and videos but it is currently not a game. Nowwhere near in fact. There are no victory/loss conditions and there is no element of danger or competition.

Things are progressing however, in the next couple of weeks, I plan to:
  • Do all the spadework necessary for implementing magic.
  • Design the frameworks for monster storage and monster AI (again, thanks to Andrew Doull for some inspiring articles on Monster AI).
  • Finish the new Angband-style Dungeon Generation algoritms.
  • Convert and implement the Cave-Generation algorithm Jakub Debski posted recently to r.g.r.d (assuming Jakub gives permission).

Beyond this, serialisation is the next obvious step, and then its the implemention of magic and monsters. After this, Kharne could be resonably described (in the loosest possible terms though) as playable.

However, I'd like to release something as soon as I can. Even if it is only to showcase what I've done so far. And to get feedback, of course. There's a horrible cliche floating about in the business world: Feedback is the food of champions, but it is (at times uncomfortably) true.

Most of all though, I want to avoid Kharne ending up as the coding equivalent of The Longest Suicide Note in History. And I think even an interactive demo would help in this respect. The smallest course corrections at this point could have a massive effect on the finished game.

What do you think? Should I be aiming for my first demo release in a couple of weeks, or hold off for a proper Alpha version?

Tuesday 13 May 2008

a new Level Generation algorithm

I've mentioned Level Generation before, and I make no secret of the fact that I'm pretty dissatisfied with the current methods I use in Kharne. They're fine for certain types of levels, but there's really too many dead ends for them to be used for anything other than labyrinthine "twisty-turny"-themed levels:



So, as light relief from studying for my part-time Astrophysics Degree*, I've been messing about with a new level-generation system for "room and corridor" type of levels, based upon the one in Angband. I've been thinking along the same lines as Andrew Doull as to how to improve that algorithm, but those improvements will have to wait for now (a thousand thanks, Andrew, by the way, for some fantastic articles).

Here's an example of my version of the Angband algorithm in action, with a simple generated mini-level, using four rooms in fixed positions (yellow represents corridors, and red and blue are soft and hard room walls respectively):



Here's another. A bit messier, but still not too bad:



But it occasionally throws up weird levels:



My first explanation for this occasional weird behaviour was a bug I must have introduced during the rewrite from C to Object Pascal, but then I started up a fresh game of Vanilla Angband and noticed pretty much the same behaviour:



Pretty gross, eh? So I think I might have to introduce a directional weighting factor in the tunneling algorithm to stop the excess of tunneling. But for now, I'll get a basic version (without much of the metadata present in the Unangband versions

* The reason I mention this is that I'm intending to enter the next 7DRL challenge with a small Roguelike with a Quantum Mechanical theme (with a twist). Quantum Physics is actually rather fun, once you get your head around it. A bit like programming, in fact.

Monday 12 May 2008

Crafting and Economics

One of the most oft-praised things about Dungeon Crawl is the fact that you can't sell things you have found in your travels in the dungeons, and as a result cash is hoarded and treated like a precious resource where every gold coin counts, and where misbuying even a simple scroll is cringeworthy. This is in contrast to the typical 'band where, with the effective availability of unlimited dungeons, the modus-operandi in the early game (well, my early games at least) seems to involve repeated scum-delving carrying back armfuls of loot to the surface to built up funds in an inflationary fashion. This differing behaviour is an example of the differing economic models that have been implemented, and which affect gameplay to a large degree.

So which type of economy do I want in Kharne? My first instinct (and one my tabletop DnD players will definitely attest to) is to be parsimonius. In my opinion 'bands are the equivalent of a Monty Haul campaign - whilst it works for them and initially is enjoyable, after a while, money loses its value and becomes more of an annoyance, not an integral part of the gameplay. However, unlike Crawl, Kharne will have a town level (actually more of a root level where all the various different dungeon branches in the game can be accessed), and whilst I think the no-selling works for Crawl, I do not want to copy Crawl's economics wholesale.

I have come up with a third approach, one I don't think I've seen implemented much in Roguelikes, although it is de rigeur in most MMORPGs. Firstly, much like Crawl, I will have no shops that buy items from players. Players can spend their hard-earned gold on buying items, but over the course of a player's lifetime, I want the sums of gold they can get their hands on to be measured in the hundreds or thousands, not the tens of thousands you find in most 'bands. But there is an alternative method of item acquirement, and it involves one of my main long term aims of Kharne:

to introduce an item crafting system as an alternative method of facilitating character advancement

If anyone has played World of Warcraft (especially post-Level 60), they will know exactly what I mean (think of the Kharne system as a combination of Enchanting and Blacksmithing). My initial thoughts on how this could be implemented are as follows:

  • Items can be disenchanted into various ingredients.
  • New Items can be constructed from these ingredients, and other drops from the dungeons.
  • These items can be made at forges randomly located throughout the dungeons and in the town level.
  • Power levels of items constructed depend both on the ingredients used and the location of the forge that was used to build the item (for example, in the town you could only make less powerful items, to make the really powerful items would require a forge in the depths of the dungeon).
  • Some of these constructed magical items could be convenant items - they grow in power with the user in some fashion.
  • Recipes for magical item creation are available randomly in the dungeon and (for a few basic items) from the town level.
  • These recipes are randomised in some fashion so that each new game does not involve grinding repetatively for the same magical items.

What I want to ensure, however I implement this is that Magical Item Creation should never be obligatory, but rather is an alternative method of character advancement - it should be seen as another way of giving a character an additional edge.

Your thoughts on this are most welcome.

UPDATE: Just after I wrore this post, I found a very interesting (And extremely extensive) thread on r.g.r.d. from a while back discussing crafting systems and the following post by R. Dan Henry in that thread gets to the gist of what I'm trying to achieve (and avoid!):

This [item creation] can be balanced if the character that can make an uber-item has some weakness that makes up for it.

Maybe you are decked out in the finest gear Central-Earth has ever seen, but still have poorer odds of actually hitting with your Awesomeness War-Blade of Universal-Slaying than a fighter would with his simple Strong Long-Axe of Human-Hacking, not to mention hit points only the most specialized mages would consider respectable.

Or maybe you have to sacrifice for every uber-item you make. Your Horn of Artifactness may be able to shatter an ordinary dungeon level when you blow it and deflect spells of darkness 90% of the time, but your maximum character level is 29 instead of 30 and your (non-inflatable brawn and smarts stats are each one lower than you rolled.

If there is a hard clock to the game, the cost in creating items could just be in time and materials.


Saturday 10 May 2008

A first attempt at Skills

The last few days I've been adding and refining skills and their effect upon creatures (of which a player is the prime example):



The skill model I've chosen is a bastardization of D&D, Angband and Dungeon Crawl, whilst influenced heavily by World of Warcraft and a sprinkling of Everquest 2 on top. Of course, since this is the first draft (and is completely different from the original Kharne), this may turn out to be horribly flawed and may need changing.

Characters have six primarily attributes: Strength, Agility, Endurance, Intelligence, Resolve and Charisma. These operate in a similar fashion to the D&D versions. Then characters have skills. These can be broken down into Fighting, Defense, Subterfuge and Magic categories. From a character's attributes and skills, all other abilities are derived (most of these in a non-linear fashion). The combat related ones are:

Evasion: Like in Crawl, Evasion is probably one of the two most important abilities. It operates in the same fashion as in Crawl, allowing a character to dodge a blow completely, but the derivation is polynomial, and it is affected by a combination of Dexterity, Defense, Armour Skill, Type of Armour Worn, and other factors (yes, I have an unhealthy fetish for Excel):



Armour: This is the character's capacity to absorb damage if he or she gets hit. This is a function of both the Armour Class of individual items and his or her skill with those types of armour.

Speed: Currently a simple linear relationship between the amount a character carries and how fast he/she can move.

Accuracy: In the old D&D days, this would be known as a "to-hit bonus" and it operates in a similar fashion. Is a function of Weapon Skill and Agility.

Damage: Bonus Damage - does exactly what it says on the tin.

Blocking: This is the chance to block the blow completely. This is different from Armour in that even if the blow's damage is so high, it cannot be absorbed, there is still a small chance it can be blocked.

Deflection: I want Kharne to have critical hits. Like the Defense skill in World of Warcraft, Deflection affects the chance of being crit.

There are two other derived stats: HP and MP, which are Health Points and Mana Points. These are a function of Race, Class, Endurance and Intelligence/Magic respectively.

All of these abilities and attributes can be modified by items (both positively and adversely in the case of cursed items). Here's a sample of some of the modifiers items can have:



The resolution mechanic is the good old D20:

Random Dice Roll + Positive Modifiers - Negative Modifiers = Some Target Number.

So there you have it, the first attempt at a rssolution/skill system. It is horribly derivative, but I think it will work adequately, with enough nuance to provide an additional element of gameplay.

Of course, I fully expect this all to completely change before Kharne is released!




Wednesday 7 May 2008

Progress Report #2

Here are some screen shots showing progress so far (click on each for a larger view).


Normal Dungeon View with Coloured ASCII


Normal Dungeon View with Monochrone ASCII


Character Information


Character Inventory

Vaults

I'm reasonably happy with my current dungeon creation algorithm - for certain types of dungeon. Its good at mausoleum-type levels, filled with rooms and twisty passages. The typical corridor length, room size, probability of a door being placed at the end of or mid-corridor, and even whether rooms can overlap are all configurable. What the algorithm isn't good at (actually, quite hopeless at), are wilderness and cave-type levels. I will probably rewrite the algorithm to generate those properly at some point in the future.

However, I'd also like to add vaults and other interesting features to the dungeon. The most popular way of generating vaults is to use a predefined map stored in a text file. For example, Dungeon Crawl Stone Soup stores the defintion of its (mini) vaults in /dat/mini.des. The current version of Unangband stores its vaults in lib/edit/vault.txt

Here is a sample Dungeon Crawl vault definition (which also contains a large amount of metadata):

#################################
# Another Ice Statue vault
#
NAME: ice2_lemuel
DEPTH: D:12-27, Lair, Swamp, Coc
TAGS: no_pool_fixup no_monster_gen
SUBST: T = TU
SUBST: W = w:20 W .:5
MONS: ice statue
MONS: ice devil w:5/blue devil w:5/ice dragon/freezing wraith/nothing w:30
MONS: white imp/ice beast w:30/polar bear/nothing w:50
MONS: white imp/ice beast w:30/polar bear/nothing w:50
KFEAT: 2 = >
KFEAT: 4 = >
MAP
T..................T
..WWW..........WWW..
.WWWWW........WWWWW.
WWWWWWwww..wwwWWWWWW
WWW3WwwwwwwwwwwW3WWW
WW343wwwwwwwwww343WW
.WW3WwwwwwwwwwwW3WW.
.WWWWwwwwwwwwwwWWWW.
..WWWwwwwwwWWW..
...WWwww12wwwwW...
..WWWwwwwwwWWW..
.WWWWwwwwwwwwwwWWWW.
.WW3WwwwwwwwwwwW3WW.
WW343wwwwwwwwww343WW
WWW3WwwwwwwwwwwW3WWW
WWWWWWwww..wwwWWWWWW
.WWWWW........WWWWW.
..WWW..........WWW..
T..................T
ENDMAP

Here's one from Unangband:

N:2:Octagon
X:9:5:14:20
D: %%%%%%%%%%%%%%
D: %%.##########.%%
D: %%..#..,,,,..#..%%
D:%%,..#.,####,.#..,%%
D:%....#.,#**#,.#....%
D:%.###+,##&&##,+###.%
D:%.#..,,#*9**#,,..#.%
D:%.#..,,#**9*#,,..#.%
D:%.###+,##&&##,+###.%
D:%....#.,#**#,.#....%
D:%%,..#.,####,.#..,%%
D: %%..#..,,,,..#..%%
D: %%.##########.%%
D: %%%%%%%%%%%%%%

I don 't intend to go into detail on how exactly these files are used. If you want more information, the source code for both roguelikes is suprisingly (for C++) reasonable. What I would like to do is use Vaults in the same way other Roguelikes. But, what I have noticed is that each individual roguelike varies how it stores its vault definition, and how much information is stored in each defintion, obviously as per the demand of the roguelike in question. So shouldn't there be a common storage format for vaults amongst roguelikes? A common Vault API, for want of a better name. After all, a vault (no matter its size, orientation and contents) is just a hardcoded subsection of the dungeon, with/without added metadata (which is particularily visible on the Crawl example above).

Further to this, should Kharne (licenses permitting and assuming the vault authors give permission, of course) be capable of reading in and using vault definitions of other roguelikes? Is this even ethical? If or if not, in any case, what would you like to see in terms of vaults in Kharne anyway? How can I make Kharne's vaults somewhere to be dangerous, alluring and rewarding all at the same time? What are the most common drawbacks of vaults you've encountered and how can I avoid them?

UPDATE: A scheme for common vault definitions was proposed on r.g.r.d back in 2003 but it appears nothing ever came of it.

Saturday 3 May 2008

Recursive Shadowcasting FOV

Although strictly speaking, I should have left it until a move advanced stage of development, a combined case of insomnia and ever-increasing irritation with the old Field-of-View system (increased by metaphorically washing its dirty laundry in public) means last night/this morning I've implemented Recursive Shadowcasting (which works beautifully for any light radius.) Plugging in Henri Haki's implementation into Delphi (from Free Pascal) was quite simple (it almost compiled without making any changes), although the co-ordinate system he uses is different from mine - I use an origin(0,0) at the bottom left (in Cartesian fashion) whereas he follows the standard VCL/LCL convention and has the origin at the top left. This video shows it in action:



The main interface has changed to what I consider to be a more slicker and less intrusive one. I'll probably change my mind again over these elements time and time again before final release.

Friday 2 May 2008

Oh what a lovely view we've got...

FOV Algorithms. Fun, aren't they?

Here's an example of the current Kharne FOV algorithm (which was lifted almost entirely from the old code), using tiles for clarity of display:



This has a light radius of 4 tiles (which the light radius of the original Kharne always was. Its...okay. However, last night, I played about with changing the light radius. Here is a radius of 5 tiles:



Whoops. The current FOV system is a crude ray-casting system using variations on Bresenham lines, and it looks atrocious when you change the light-radius. To any light-radius other than 4. I'm eventually going to have to change this. But for now, the light radius stays at 4 and any plans for dynamic light sources be damned.

A quick search of the web revealed many different FOV algorithms. The most promising one appears to be Björn Bergström's Recursive Shadowcasting methods. My C++ is extremely rusty, but there are a couple of FreePascal implementations out there that should^H^H^H^H^H^Hwill be easily portable to Delphi.

Should be a lot of fun when I get round to recoding the FOV.

Thursday 1 May 2008

What the RNG giveth, the RNG taketh away...

Not a direct Kharne-related post, but what follows is one of the reasons I love roguelikes so much, and hopefully someday, Kharne will have the same kind of atmosphere.

I started a new Crawl game the other night, and unusually for me for Crawl, I chose a non-Troll (I have an aversion to the Crawl hunger system born of too many deaths by starvation). I went with a Mountain Dwarf Fighter and almost immediately found a +0 gold dragon armour on the very first dungeon level. Now dragon armour gives an obscene AC for starting characters (at the cost of ruining your EV) along with lots of resistances.

Wearing it, I quickly found I was pretty much indestructible. Ogres and orc warriors were being two-shotted, and couldn't damage me. I stomped my way down to D10, and blatted the top levels of both the Orc Mines and the Lair (with enchanting the armour repeatedly, my AC was 30+).

I spotted an entrance to the Elven Halls. Now, historically, I've stayed out of this place because the amount of firepower those little 'e's can put out is obscene (and has bitten me severly before), but overconfidence got the better of me. So I went down, stomped about a bit, came back up and rested, and then went back down and then bamm!! - you know what happens next:

"Cast into the Abyss (deep elf mage)"

Oops. I panicked for a bit (I've not been to the Abyss for a long time, and have never been ported there), and then encountered an Executioner. Result, one dead mountain dwarf.

Obviously the karma of me getting an overpowered armour on D1 resulted in my death. Roguelikes, don't you just love 'em?
Anyway, here's part of the Morgue file:

Dungeon Crawl Stone Soup version 0.3.4 (crawl-ref) character file.

11855 Blorg the Cleaver (level 11, -4/90 HPs)

Began as a Mountain Dwarf Fighter on Apr 30, 2008.

Was a High Priest of Okawaru.

Slain by an Executioner (13 damage)

... in The Abyss on May 1, 2008.

The game lasted 01:36:17 (16959 turns).

Blorg the Cleaver (11855 points)

Race : Mountain Dwarf Res.Fire : + . . See Invis. : .
Class : Fighter Res.Cold : + + + Warding : .
Worship : Okawaru***** Life Prot.: . . . Conserve : .
Level : 11 Res.Poison: + Res.Corr. : .
Exp : 15335 Res.Elec. : . Saprovore : . . .
Next Level : 20084
Exp Needed : 4749 Sust.Abil.: + Rnd.Telep. : .
Spls.Left : 10 Res.Mut. : . Ctrl.Telep.: .
Gold : 1121 Res.Slow : . Levitation : .
Clarity : . Ctrl.Flight: .
HP : -4/90
MP : 7 Weapon : +4,+3 dwarven hand axe of chopping
Str : 22 Armour : +4 gold dragon armour
Int : 7 Shield : +0 dwarven shield
Dex : 12 Helmet : +2 helmet
AC : 32 Cloak :
Evasion : 2 Gloves : +3 pair of gloves "Ygimeoj"
Shield : 7 Boots :
Amulet :
Play time : 01:36:29 Ring : ring of protection from magic
Turns : 16959 Ring : ring of sustain abilities


You were in the Abyss.
You worshipped Okawaru.
Okawaru was exalted by your worship.
You were not hungry.

You visited 5 branches of the dungeon, and saw 20 of its levels.
You visited the Abyss 1 time.

Inventory:
Hand weapons
a - a +4,+3 dwarven hand axe of chopping (weapon)
n - a +1,+2 dwarven vampiric hand axe
J - a +3,+1 hand axe
Missiles
h - 12 +0 darts of ice
Armour
c - a +0 dwarven shield (worn)
g - the +3 leather armour of Clicank
(You found it on level 4 of the Dungeon)
It greatly protects you from fire.
It lets you teleport.

i - a +2 helmet (worn)
k - a +4 gold dragon armour (worn)
r - a +0 dwarven spiked helmet
s - the +3 pair of gloves "Ygimeoj" (worn)
(You found it on level 4 of the Dungeon)
It greatly protects you from cold.

Magical devices
t - a wand of flame (8)
y - a wand of confusion (3)
E - a wand of polymorph other (7)
O - a wand of confusion (4)
Q - a wand of slowing (7)
R - a wand of frost (8)
Comestibles
d - 4 bread rations
Scrolls
b - a scroll of torment
j - a scroll of detect curse
q - 7 scrolls of remove curse
I - a scroll of enchant weapon III
U - a scroll of paper
Jewellery
f - a ring of sustain abilities (left hand)
l - a ring of protection from magic (right hand)
o - an uncursed ring of ice
z - an uncursed ring of poison resistance
B - an uncursed ring of protection from fire
T - an uncursed ring of magical power
Potions
m - a potion of slowing
u - 2 potions of levitation
v - a potion of cure mutation
w - a potion of speed
Books
p - a book of Frost
A - a book of Hinderance
G - a book of Power
Magical staves
F - a staff of summoning


You had 1 experience left.

Skills:
+ Level 9 Fighting
+ Level 14 Axes
+ Level 1 Throwing
+ Level 8 Armour
+ Level 11 Shields


You had 10 spell levels left.
You didn't know any spells.

Overview of the Dungeon

Branches:

Temple: D:5 Orc : D:6 Elf : Orc:4 Lair : D:8
Swamp : Lair:2

Altars:

Okawaru: D:7, Orc:4
The Shining One: D:10
Beogh: Orc:3, Orc:4

Shops:

D:5: ? D:6: = Orc:3: *


Innate Abilities, Weirdness & Mutations



You have tough skin (AC +1).



Message History

The Executioner hits you but doesn't do any damage.

You hit the Executioner.

The Executioner is lightly wounded.

The ynoxinul hits you.

* * * LOW HITPOINT WARNING * * *

The Executioner hits you!

You die...



#

# .#

. . #

. .#.

. . #.#

....#.#.#

#.{1@#

#.{.3#.......#

...#.#. ...##..

. . .{ ...#

. .. ....

# ... #...#

##{ .#.#

.# ..#





----------------------------------------

Grand Total: 466 creatures vanquished

Notes
Turn Place Note
--------------------------------------------------------------
0 D:1 Blorg, the Mountain Dwarf Fighter, began the quest for the Orb.
0 D:1 Reached XP level 1. HP: 16/16 MP: 0/0
230 D:1 Reached XP level 2. HP: 21/23 MP: 1/1
1005 D:2 Reached XP level 3. HP: 29/29 MP: 1/1
1851 D:3 Reached XP level 4. HP: 32/37 MP: 2/2
2174 D:3 Reached XP level 5. HP: 36/42 MP: 3/3
2822 D:3 Defeated Garg's ghost
2822 D:3 Reached XP level 6. HP: 31/50 MP: 3/3
3012 D:4 Noticed Jessica
3018 D:4 Defeated Jessica
3207 D:5 Entered Level 5 of the Dungeon
3321 D:4 Defeated Monsty's ghost
3741 D:4 Reached XP level 7. HP: 56/57 MP: 4/4
3845 D:4 Noticed Ijyb
3861 D:4 Defeated Ijyb
3941 D:4 Identified the +3 pair of gloves "Ygimeoj" (You found it on level 4 of the Dungeon)
4280 D:5 Noticed Edmund
4308 D:5 Defeated Edmund
4436 D:5 Reached XP level 8. HP: 40/63 MP: 5/5
4817 D:5 Identified the +3 leather armour of Clicank (You found it on level 4 of the Dungeon)
4909 Temple Entered the Ecumenical Temple
4966 Temple Became a worshipper of Warmaster Okawaru
5202 Orc:1 Entered Level 1 of the Orcish Mines
5910 Orc:3 Acquired Okawaru's first power
6199 Orc:4 Entered Level 4 of the Orcish Mines
6531 D:7 Reached XP level 9. HP: 61/69 MP: 5/5
7527 Lair:1 Entered Level 1 of the Lair of Beasts
7557 D:8 Noticed Blork the orc
7567 D:8 Defeated Blork the orc
9406 Lair:1 Reached XP level 10. HP: 67/79 MP: 6/6
11998 D:10 Entered Level 10 of the Dungeon
12762 D:11 Defeated Brag's ghost
12965 D:11 Reached XP level 11. HP: 83/88 MP: 7/7
14995 Orc:4 Gained mutation: You have tough skin (AC +1).
15399 Elf:1 Entered Level 1 of the Elven Halls
15722 Orc:3 Acquired Okawaru's second power
16790 Elf:1 Cast into the Abyss (deep elf mage)
16790 Abyss Entered The Abyss
16959 Abyss Slain by an Executioner


Progress Report #1

Its finally time for a progress update. Inspired by the categorisation given in How to Write a Roguelike in 15 Steps, I've broken down the coding of Kharne into a number of discrete areas. The current areas of the rewrite either completed or in a reasonable playable state are:

Game Mechanics
I have a complete document that specifices the game mechanics I'm using. The original Kharne used AD&D, but the rewrite is using a system influenced by both Angband and Crawl. These may need tweaking during playtesting since according to the old saying, "no plan ever survives contact with the enem^H^H^H^Hplayers."

Data Storage
Read-only config and item information is currently stored in an SQLite database. For any modifiable data, e.g. savedata, compressed text files will be used.

Character Creation
This has been hived off into a seperate DLL to avoid bloating the main code too much. This is, bar any tweaking to the game mechanics, finished and complete.

Level Generation/Navigation
The dungeon algorithm I'm using is a heavily modified version of the one used in the original Tyrant by Mike Anderson. I've extensively modified it and parameterised it to enable the production of a much wider variety of levels than it was originally capable of. I will add in additional algorithms for different level times eventually.

Display
I'm using plain old GDI with Double Buffering. The basic viewport is running, in tiled mode, at well over 100 fps on an old P4 2.8 Ghz PC. The framerate for ASCII mode is off the scale. Incidentally, Kharne doesn't use any sort of text handling for ASCII mode - the characters are blitted graphically to the screen. I hope to eventually use this to enable smooth real-time rotation and zooming of the play area, which, to use a technical term, "cool".

Item Generation
I can generate a wide variety of magical and non-magical items, either random, or of a specified quality and type. I have also written an external program that uses the same item code to produce vast numbers of items for future analysis and statistical purposes.

Inventory and Item Handling
The '@' can pick up, wield and remove a wide variety of items. The effects these items have on player statistics isn't completely implemented, however.

Things yet to do, in approximate order, are (deep breath, this is still quite a big list):

Morgue/Death Handling
Time Handling
Saving/Loading
Magic
Monsters
Monster AI
Victory/End Game Handling

The current roadmap from here is to try and finish what is remaining on inventory handling and then make a start on the remaining items mentioned above. Unfortunately, a playable release will be a few weeks off yet.