Posts in category 'nethack'
Just released version 3.6.7-2 of my old NetHack port for the Nintendo DS with some QoL improvements and bug fixes. It’s amazing how, when you step away from a project for, oh, 15-ish years, you start to notice little warts that you’d just gotten used to…
Don’t ask me why, but I restarted tinkering with my old DS port of NetHack! I forgot how much fun it is coding for platforms like the DS. It’s just so… simple.
I was also reminded that, you know, my port plays really damn well. I forgot how many hours I logged in it! So, if you’re a NetHack fan, own a DS, and have a flash card, all four of you can try it out!
https://github.com/fancypantalons/NetHack/releases/tag/NetHackDS-3.6.7-1
Updated my Nintendo DS port of NetHack to upstream version 3.6.6! Why? Because I can, and I had some time over my lunch break, that’s why!
Nethack == Gambling
So, it’s winter here in the northern hemisphere (although, given the weather we’ve been having lately, you wouldn’t know it), and I now have a renewed passion for two of my favorite hobbies: knitting and Nethack.
Mmmm… juxtaposition.
Anyway, since the start of my “season” I’ve created and killed off a whole host of characters, during which time I’ve often felt the nearly irresistible urge to throw my DS against the wall. And this fact begs an interesting question (to use that phrase colloquially): Why on earth do I do this to myself??
Now, for those not in the know, Nethack is part of a family of games known as Rogue-likes, named after their original progenitor, Dungeon Crawler. Err, I mean, Rogue. Anyway, this family of games all have a few things in common (which is why they’re a family, duh):
First, they’re almost invariably centered around a character the user controls, who is then responsible for exploring a world, encountering bad guys, and eventually progressing to the endgoal, whatever that may be. In the case of Nethack, it’s a dungeon, and the player’s goal is to descend to the bottom of that dungeon, retrieve the Amulet of Yendor, and return it to his god, whilst not dying along the way.
Second, most roguelikes involves lots of items, armour, weapons, scrolls, wands, spellbooks, and so forth, that the player can acquire along the way, either by finding them randomly, looting from corpses, or buying or stealing from shops.
Third, those items? They’re unidentified at the outset. For example, in Nethack, you may come across a scroll with a name like “NR 9”, but you’ll have no idea what it actually does. So a large part of the game is focused on various tricks to identify those items. Oh, and of course, items can be good or bad, so that scroll may have been a scroll of enchant armour, or it may have been a scroll of destroy armour. So you can’t just go randomly reading scrolls, zapping wands, and trying things on (unless you plan to die quickly).
Fourth, when you die, you’re dead. No take-backsies. No save points. Nadda. You can, of course, save your current game and pick it up later, but if you die, that save state is gone. Toast. Kaput. You’re boned. So you have to be very careful. And avoid stupidity (the YASD, or Yet Another Stupid Death, is a common experience amongst Nethackers).
Fourth, and most importantly, the level layout, the positions of the items and their identities, the enemies, they’re all random. So each game is completely different.
So, back to the question. Why do I do this? YASD after YASD, I still come back for more, and I like it. And it’s that fourth item that, I think, is the key.
You see, gambling works by a pretty simple reward system, combined with the thrill of risk taking. Of course, anyone who’s spent any time in a casino understands what I’m talking about, here. Notice any similarities? Like any other form of gambling, Nethack provides randomized rewards to the players in exchange for risk, and as one progresses in the game, the risk only gets more pronounced (since the player has more and more invested in their character). One game, they may find a wand of wishing on the second level. The next, they might hit a poly trap in the Gnomish Mines, blow out their armour, and get killed by a cockatrice. That kind of randomized reward system plays with the brain in the exact same way that, say, Blackjack does.
So you really have to wonder, are there problem Nethack players out there? Was Rogue really the first Evercrack? I’m betting the answer is ‘yes’… the only difference is, unlike WoW, the Rogue-like family has maintained a relatively low profile, and so you don’t see the kind of widespread addiction we now see in modern MMORPGs.
Victory is Mine!
Well, I won the battle, anyway, even if the war is still ongoing. Word wrapping appears to work, menu items wrap, larger font sizes are now fully supported. And it looks mighty fine! And so, NetHackDS version 1.10 is now available!
Of course, now I have to move on to the myriad other features on the list.
Slow, Inexorable Progress
Very very slow… or, at least it feels that way. In reality, I can’t really complain. Word wrapping, even nice paragraph-reflowing word wrapping, is in and works quite nicely. Meanwhile, the command window is now finished, and supports snazzy scrolling when it’s necessary (of course, the default font still doesn’t require it, but switching to, say, the map font, which is 8x16, results in four pages of commands). It’s lightening quick, too, unlike the rest of the rendering code (yay large backbuffers and DMA copies). Meanwhile, the menu item wrapping code is… coming along.
Of course, the menu code has been a constant thorn in my side… I’m starting to realize I really need to go back and rethink how the code is designed, but at this point, I just want to get it working and move the heck on. Of course, that may be easier said than done. Currently, the big problem is that, previously, I could assume menu pages were the same size. After all, every item had the same height, so once the page size was calculated, it was basically constant. But now, with items being wrapped, they may take up two or even three lines in the menu, and I suddenly need a much smarter algorithm for determining how to page forward/back through the menu. It’s all quite tedious… which is why, I suspect, I left it for so long. sigh
Update:
Well, in a wave of inspiration, I managed to get the scrolling issues fixed before I left for work this morning (yay for extremely simple solutions). There’s still at least one crasher I’ve come across, but so far things are looking pretty darn good, if I do say so myself.
Word Wrapping For The Win
While development has slowed considerably on NetHackDS, partly due to me play… err… testing, partly due to me just needing a bit of a frickin’ break (and partly due to the excessive drinking I did during our company Christmas party, which left me nonfunctional for much of today), I have been putting some effort into one of the more difficult enhancements I’m doing to the codebase: adding proper word wrapping.
The impetus of all this started with a comment from one of my users who noted that, due to his/her poor vision, they’ve found my port rather difficult to use, as it makes use of a fairly small font. As such, they were wondering if I could add support for larger font sizes, and I, of course, said I’d take a look at it. It also happens that the only major remaining “known issue” in the code is one of text clipping: since the DS can only display, oh, maybe 65 columns of text, while much of the text in the game is designed for an 80-column display, there are a number of instances where the text is just chopped off on the right-hand side. And this is related to the font size issue because both problems require the same solution: word wrapping.
Now, the most basic word wrapping algorithm one might come up with, where you simply chop text where it’s too long, and print the remaining portion on the next line, does the job well enough, but it’s pretty unsightly. You end up getting things like this:
Before:
Hello, this is a really long piece of text I'm using for an example. And here is another line of text.
After:
Hello, this is a really long piece of text I'm using for an example. And here is another line of text.
Ideally, in a situation like this, what you really want is for the word wrapping engine to understand that the text is really a paragraph, and the words shouldn’t just be wrapped, but reflowed as well, so you get something like:
Hello, this is a really long piece of text I'm using for an example. And here is another line of text.
instead. So, being the wildly talented programmer that I am, I reinvented yet another wheel, wrote a reflowing word-wrapping algorithm, and voila! Fancy reflowed text. And it looks mighty fine, too. But there’s a problem. In order to write an algorithm like this, you have to identify paragraphs. Now, it just so happens that blank lines are usually used to separate paragraphs (you need only look at this post to see that), and so it’s pretty easy to identify where one paragraph starts and the other ends. But, NetHack also likes to generate tabular data like this:
No Points Name Hp [max] 1 48117 brettk-Val-Hum-Fem-Neu died in The Gnomish Mines on level 12. Killed by an Elvenking. - [115] 2 39115 brettk-Val-Hum-Fem-Neu died in The Gnomish Mines on level 10 [max 11]. Killed by a vampire lord. - [79] 3 29901 brettk-Bar-Hum-Mal-Neu died in The Gnomish Mines on level 11. Killed by a hallucinogen-distorted giant ant, while helpless. - [105]
and if you identify paragraphs by blank lines, and you reflow text, you end up with:
No Points Name Hp [max] 1 48117 brettk-Val-Hum-Fem-Neu died in The Gnomish Mines on level 12. Killed by an Elvenking. - [115] 2 39115 brettk-Val-Hum-Fem-Neu died in The Gnomish Mines on level 10 [max 11]. Killed by a vampire lord. - [79] 3 29901 brettk-Bar-Hum-Mal-Neu died in The Gnomish Mines on level 11. Killed by a hallucinogen-distorted giant ant, while helpless. - [105]
Notice how the rows are all jammed together. See, to the word wrapping engine, this looks like one big paragraph, thus it wrapped it accordingly, and the result is an unreadable mess. So, in this case, you don’t want to reflow the text. In fact, there’s really no nice way of handling this, so you’re best off just using the ol’ chop-and-print approach, as at least it somewhat preserves the tabular layout. But what the heck do we do, now?
Well, the NetHack putstr() call that is used to write text to a window, and is the entry point I implement, takes an attribute, which normally specifies bold, underline, etc, for the text. So, I created a new attribute bit, 0x1000, which basically says “don’t reflow this text”. I then went into the NetHack core (yeah, more core mods… I don’t like it, either) and altered the topten code so that, for the NDS version, it specifies this “dont reflow” attribute. This same attribute is also used wherever files are paged out (such as the in-game help text). But that does mean that, in effect, I’ve had to special case the NetHack core in a couple places in order to get the correct wrapping effect… basically, the solution sucks. Unfortunately, I don’t know of a better one.
But, on the bright side, the word wrapping works! And I’m using the same code in the status updates, the text windows, the message output, and eventually the menu code. Then, I just need to create a scrollable command window (the current one is entirely static), and the new, non-clipping, larger-font-capable NHDS will be ready! Ish.