Saturday, September 20, 2014

jedi

Since the last post was entirely about coding, this one will be entirely about concepts for the game.  The psion was the first idea I had for a new role in the game.  Since that flash of creativity hit me, brainstorming about the psion has brought me in many directions.  I've come up with several ideas that would affect game play for all roles.

I view the psion as being the brother to the monk role.  Penalties would be given for wearing armor and wielding weapons, however, eating corpses wouldn't make you feel guilty.  Instead of gaining intrinsics like poison/fire/cold resistance at increasing experience levels, psions would gain mental abilities.  I'll lay out the monk's abilities first, then my psion's abilities.  Note that the psion abilities are all, very much, subject to change:

Monk in Nethack:
XP Lvl 1: speed, sleep resistance, see invisible
XP Lvl 3: poison resistance
XP Lvl 5: stealth
XP Lvl 7: warning
XP Lvl 9: searching
XP Lvl 11: fire resistance
XP Lvl 13: cold resistance
XP Lvl 15: shock resistance
XP Lvl 17: teleport control.

Note that, in slashem, fire, cold, and shock resistances are now techniques, not intrinsics.

Psion in greghack:
XP Lvl 1: intrinsic telepathy (like you get from eating a floating eye corpse)
XP Lvl 3: see invisible
XP Lvl 5: extrinsic telepathy (like you get from wearing an amulet or helm of ESP)
XP Lvl 10: flying
XP Lvl 15: detect monsters (like the blessed potion, but always on)

Detect monsters is pretty powerful, so I'm up in the air about that.  I used to have phasing at level 20, but that's WAY too powerful.  I'm thinking of maybe making that a limited-time ability from invoking the psionic quest artifact, which I have not implemented nor spent much time thinking about.

Psion Techniques are similar to monk techniques at the moment, with some exceptions.  The main reason behind getting rid of chained blitz is that I still haven't quite figured out how it works.  psi strike and psi healing are the same as the monk's chi strike and chi healing.  See what I did there?  Changing "chi" to "psi"?  Brilliant.

Monk's techs:

XP Lvl 1: pummel, dash, chained blitz
XP Lvl 2: chi strike
XP Lvl 4: chi healing
XP Lvl 6: elemental fist
XP Lvl 8: draw energy, telekinesis
XP Lvl 10: ground slam
XP Lvl 11: ward fire
XP Lvl 13: ward cold
XP Lvl 15: ward electricity
XP Lvl 17: spirit bomb
XP Lvl 20: power surge



Psion's techs:
XP Lvl 1: pummel, dash
XP Lvl 2: psi strike
XP Lvl 4: psi healing
XP Lvl 6: elemental fist
XP Lvl 8: draw energy, telekinesis
XP Lvl 10: ground slam
XP Lvl 15: psychokinesis
XP Lvl 17: spirit bomb
XP Lvl 20: power surge

Telekinesis is taken from the Jedi patch.  I actually like the author's implementation.  With telekinesis, you can pick up objects from a short distance and you can interact with traps (disarm and trigger them).  Psychokinesis is different.  You'd be able to move a monster, item, or yourself from an arbitrary location (within a limited range) to an arbitrary location (within a limited range).  Another option would be, instead of moving the object to an arbitrary location, you would pick a direction in which to move it, though I prefer the former.  There is already code in place to handle "hurtling" monsters and yourself through the air.  Of course, they are in two different functions, hurtle and mhurtle, and I'd have to code a third to manage the hurtling of items through the air (ihurtle?).  I'd like to combine all three functions into one, because that would only make sense.  Anything with coordinates (i.e., a location on the map) should be able to be hurtled by the same function.

Moving on... so I want to be able to hurl monsters through the air.  I followed that thought to its logical conclusion, and decided that I should implement a system of picking up, and throwing, monsters.

Saturday, June 14, 2014

Out of retirement!

I had given up on writing a variant.  The usual excuses prevailed: work, the code is insane, I discovered Kerbal Space Program, etc, etc.  But, I'm taking a break from Kerbal Space Program because of an ATI graphics driver bug that has been driving me crazy.

But, I'm out of retirement!

I was in the middle of a solid game, playing as a female human rogue, and had stumbled across some very good luck: two magic lamps (both resulted in wishes), two bags of holding, etc, etc.

Then I ran into a bug that almost resulted in my character's death (by starvation).  I was very lucky to be saved by a puma's attack, and quickly #prayed (I was fainting at this point), killed the puma, then saved the game.


The main reason I was lucky about surviving is that I was able to save the game and copy the save file so I can reproduce the bug easily.  Whatever your feelings might be when it comes to copying nethack save files, I guarantee I'm more passionate about having solid test cases for bug reproduction and bug fix verification.

Anyway, a while back I blew away my Arch Linux installation because the folks over at Arch started doing crazy things that broke everything for me, so I switched to Debian.

I've never successfully built the nethack-3.4.3 code on any OS other than Arch and FreeBSD.  I'm running Debian now, and I can get the source with a simple apt-get source nethack, but unlike the OS's with ports trees, it doesn't come ready to rock.  I still have to figure out all the crazy config options and, traditionally, I get frustrated and give up before working through all the errors (please leave a comment if you have easy steps for compiling in Debian).

So I dusted off my old piece of junk $110 desktop computer (brilliant buy, I love this thing) that has FreeBSD installed and will work on the fix there.  Yes, I did actually have to dust it off, please don't make fun of me for that.  I'm updating the system now, and then I'll work on the fix.

Once I have a fix, I'll write up and post my root-cause analysis along with the patch and the saved game that triggered the bug so others can verify the fix.

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

Update: I figured out how to build nethack in Debian.

Sunday, July 21, 2013

GAHHH_NEW_POST!

Now that I'm sure everyone has stopped visiting this blog, I am back!  I was very busy for a while at work as we had a very important deadline approaching for a couple of months.  But that deadline was reached, and good news abounds!  My tiny little start-up was very recently acquired by the best possible company that could've acquired us.  Everybody's happy.

Now, back to nethack.  I haven't played in so long that I've forgotten a lot of the little nitty-gritty spoilers I used to know.  I once again have to look up specific prices of scrolls, potions, rings, etc.  Of course, I'll never forget that my three favorite rings, slow digestion, free action, and levitation (in that order), are all 200 Zk.  Regardless, I'll probably need a little ramp-up time to refamiliarize myself with the little details of the game, as well as the intricacies of the gameplay, before I can jump back into the code.

What's important to take away though, is that this blog is not dead.  It was just wearing an amulet of live saving (ugh, I know, awful joke.  I'm here all week).

Secondly, what's important to take away is that I finally finished my tourist game.  Tourist is one of the best roles in the game.  The early game is very difficult, but the quest artifact is arguably the best in the game, and the quest itself yields tons of loot.

One fun little stupid thing I like to do is chat with Death.  The background is that there are four Riders of the Apocalypse, explained in great depth in The Book of Revelation.  It's a great read, and if you haven't read it, it's probably one of those things you should read aloud to your children at bedtime.  In the words of my boy TJ (Thomas Jefferson), it is "merely the ravings of a maniac, no more worthy nor capable of explanation than the incoherences of our own nightly dreams."

On the Astral Plane, in nethack, you will find three of these Riders: Famine, Pestilence (also know as Conquest in the BoR), and Death.  If I am able, I always make a point to chat with Death, because he gives some insight into who the fourth Rider is:



This actually makes a lot of sense.  You spend the game going through a dungeon killing thousands of creatures.  I can't really think of a better definition of "war" than that.










Wednesday, April 10, 2013

busy busy busy

Sorry, updates are going to be slow for a little while.  My company is in crunch mode for our next release, so I'm just writing to let y'all know, I haven't abandoned the blog, or my variant.  I haven't abandoned nethack either, even though I haven't played my awesome tourist game in ages.  The PYEC is such a good artifact.

In the meantime, my mouse's wheel click has started pasting text when it opens links in new windows, as opposed to before when it would open links in new tabs without pasting.  All my searching so far has told me that is default functionality in X, and unless I want to hack X (a possibility...), I'm going to have to deal with it.

I wonder why it didn't paste before?  It doesn't on my Arch Linux system, which is running X, just on my Linux Mint system.  Maybe some update got me.  The nice thing about minimalist distributions is that they don't get cluttered with unwanted stuff.

Wednesday, March 27, 2013

Next Steps

I've been slow to update recently, since my company is releasing a new version of its software at the end of the week...

But!  My next step is to merge struct you with struct monst, or rather, take out redundant data, like location, alignment, intrinsics, etc, etc, etc, etc, etc.  I want to treat monsters and the player more equally, though I realize there will be some things that are specific to struct you.  the game has a global struct you u, and a global struct monst youmonst, and in some cases, it seems arbitrary which one is used.


On an completely unrelated note, I stumbled across this gem the other day on one of those 'horrors of coding' sites:


    static boolean isTrue(boolean b) { 
        HashMap map = new HashMap();
        b = ! !b;
        if (!(!(b == !b)) == false) {
            map.put(false, !(!(b != !b)));
        }    
        return !map.containsKey(b) & (!true | !false);
    }

I believe this is Java code.  It may also work in JavaScript but, fortunately, I'm not familiar with JS.  It may be the most amazing piece of code I've ever seen, maybe even better than x[strlen(x)] = '\0';.


Friday, March 22, 2013

sporkhack

I was inspired by the subject line of a co-worker's email: "+1 Gauntlets of Coding".  It was just an email with a link to wrist braces for carpal tunnel syndrome, but I really like the sound of Gauntlets of Coding.  I_have a couple ideas: when wearing Gauntlets of Coding, you movement speed will increase only when using the travel command.  Or, it gives you jumping.  Both are pretty big stretches at puns about using goto statements to either travel faster, or jump through code...  yeah...  I'll probably make Gauntlets of Coding a compile-time option, defaulting to not include them.

Moving on...

Sporkhack!  I've been spending more time playing sporkhack, and I have to say, what a fucking brilliant game.  So many changes.  From partial resistances, to sacrifice gifts based on XP level, to chaotic Knights, to variable telepathy range, to new items like gold dragon armor, shield of light, Dirge, etc... fucking brilliant.

Where some variants put a lot of effort into nice ncurses interfaces, sporkhack is all about gameplay. I'm seriously considering ditching the slashem source as my code base for my variant and starting with sporkhack instead, since there are just too many features from sporkhack that I like, and most of them are the bag of poo:



I do have two gripes about sporkhack, and they are very, very minor.  One, I don't like the new character creation screen.  When I start a new nethack game, I know what I want to play as, so I just run: $ nethack -u greg-rog-hum-fem for example, and the game starts.  Even if you do that in sporkhack, you still get taken to this screen:


So you have to press "." to start playing.  I realize how this starting screen can be helpful to new players, since it lets you know what combinations of role, race, and alignment are allowed, but I guess I'm just old and stubborn and like the vanilla nethack character creation system better.  Also, I sometimes run into a bug where, when starting a new game, I get stuck in a corner with no map.  I even tried starting as an archaeologist to see if I could dig my way out, but no dice:




Has anyone else run into this?  I'm using the sporkhack-svn package from the Arch User Repository, so it's possible that this bug is specific to that code.

...

When it comes to debugging, my strategy revolves entirely around printk (printf if I'm in userland).  I don't use gdb because I don't know how.  I've always wanted to learn... but it just seems too daunting of an exercise.  Sometimes I'll resort to objdump or readelf in a bind, but mostly, I just print out whatever things I'm curious about.

Is there a good way to dump debugging messages in nethack, other than using the pline function?  If not, I'll write a patch that will log debug messages to a log file.  Then anyone could just call something like nh_trace( LOG_WARNING, "blah blah blah %s, blah %d", ... ) instead of using pline, which interferes with gameplay.

Tuesday, March 19, 2013

Girl Power!

Who doesn't love numbers?  Well, sadly most people, and yet they still remain the best way of measuring things.  Go figure.

Special thanks to NetHack 4's maintainer, ais523, for the data.

These numbers do not include games that were started but never finished.  The player either had to die, ascend, die, quit, die, escape, die, or be killed.  There were 2788 games in total.

First, let's look at starting role vs. max xp level:


Okay, nothing too surprising here.  Valkyrie remains a solid choice.  Wizard has a tough early game but can become very powerful in the mid and endgame.  Tourist did remarkably well, meaning there are quite a few badass NH4 players out there.

One thing I'd really like to point out is that the Monk dominates the early game.  Lots of people dump on the monk, I don't know why, because they're not bad.  Only drawback, of course, is that they can't wear Gray or Silver Dragon Scale Mail unless at a high enough level to get over the big to-hit penalty.

Role vs. points is pretty similar, no surprise there, so I won't bother with the graph. How about ascensions by role?


Once again Valkyrie, Wizard, and Tourist take the lead!  More importantly, I'd like to see role popularity, because that will clearly affect the number of per-role ascensions.  (Thanks to the HockeyblogAdventure for pointing out the typo in the below graph title.  I'll maybe fix it when I get home from work).

This confirms one of my theories about Barbarians: they're boring to play.  Wizards are always interesting, though it's sad to see a lack of love for my favorite role, the Rogue.  It also confirms that Valkyries are strong role.  They are relatively unpopular (perhaps because they are so strong) yet have the most ascensions.

Also interestingly, people prefer to play Male characters, but Females have more wins.  Only ~24% of the players used female characters, but they accounted for ~64% of the ascensions:


I usually play female characters because I figure that if I polymorph into an egg-laying monster, like a dragon or cockatrice, I can make myself lots of awesome pets.  On the other hand, if an egg hatches in a male character's inventory, there's a 50% chance of it being tame.  On one hand, I don't use the egg-laying trick in most games, but on the other hand, when I do use the trick, I get lots and lots of pets out of it.  I'm curious what other peoples' preferences are.

Anyway, this post was just about some fun with numbers.  Let me know if there are any other interesting or more complicated stats you want to see.  I use the R project for a stats program, and it is superb.  Here are the fields with which I have to work:


"points"    "deathdnum" "deathlev"  "maxlev"    "hp"
"maxhp"     "deaths"    "deathdate" "birthdate" "uid"
"role"      "race"      "gender"    "align"     "name"
"charname"  "death"     "conduct"   "turns"     "event"
"carried"   "starttime" "endtime"   "gender0"   "align0"
"xplevel"   "exp"       "mode"


Also let me know if there are questions about what the fields mean.  I think the most confusing one might be align0 and gender0 which refer to starting alignment and gender, where as align and gender refer to alignment and gender at the game's end.  I don't know what the event field is.

Thursday, March 14, 2013

code restructuring, again

I applied the CK patch my kernel last night to give the Brain Fuck Scheduler and Budget Sector Queue I/O scheduler a try.  I'm more interested in the I/O scheduler since disk access is much slower than context switching, though in theory, BFS should give me ~2% better performance... 2%... yay!  Also, I know more about storage than CPU architecture, so I have a better idea about what's going on.  I gotta say though, I'm impressed with how quickly BFQ hits my external drive.

Moving on...

It's a sad day in Boston.  The Pats traded Wes Welker.  Everyone's pissed.

Moving on...

I came up with a better way to do code restructuring.  First, techniques can stay in their crazy switch block.  You can only do one technique at a time anyway, so there's no point in using function pointer madness.  However, none should return inside their case, rather, they should just break out instead and a single return will be placed at the end of the function.  Each should also specify their own timeouts.  Some do, some use the timeout at the end, some don't even have timeouts:



This is true of techniques and magical effects in general.  Being effects, all they do is modify data, so they can return void.  If it matters whether you succeeded or not, you can always check the condition after it returns.  Instead of linked lists for weapon effects, it will just be a dynamically sized array of effects, and I can loop over the switch blocks and apply each effect in turn.

Tuesday, March 12, 2013

random thoughts

I haven't had much time lately between a Bruins double header that started last night and heading up to VT to ski last weekend.  By the way, don't get stuck in chest deep powder, it fucking sucks.

Anyway, some ideas:
 - Weapons dipped in potions of sleep have a chance of putting a non-sleep resistant monster to sleep on a hit.
 - Weapons dipped in potions of acid do some acid damage on a hit.
 - Weapons dipped in potions of paralyze have a chance of paralyzing a monster for a random, short duration on a hit.
 - I'm sure there are some other cases.

 - Lenses of Infravision
 - Sunglasses (Lenses of Shade?) that would protect against blinding light-based attacks, and maybe give you +1 charisma when worn because they are so cool.
 - Artifact lenses that give you some sort of gaze attack when invoked at the cost of some magic power.

 - Shields of fire, ice, acid, whatever, from sporkhack, have a chance of doing passive damage to a monster if the monster does not hit you and you get the message that you deflected the attack with your shield.

Soldier role:

Soldiers can reach expert in firearms, saber, and maybe skilled in long sword and a few other weapons.  They would start with a pistol, as well as typical soldier gear: low boots, leather gloves, saber, dented pot, leather armor, tin whistle, and a few K or C rations.

I can't think of a good first sacrifice gift.  I don't just want to make it a gun because you'll have plenty of opportunities to pick up a gun later.  Maybe a magic magazine, base item bag, that generates a random number of bullets when invoked... but then again, you also have plenty of opportunities to pick up bullets throughout the game.  Maybe a special gun, a Magnum, base item pistol, that does more damage than a pistol and has a chance of stunning and/or knocking back an opponent like a monk's stunning strike.

The quest artifact would be The Holy Hand Grenade, generated blessed (since it's Holy), and the base item is a stick of dynamite (it's already in the code, not randomly generated though, so you'd need to wish for one).  Instead of the long fuse sticks of dynamite have, an armed Holy Hand Grenade would detonate in 3 turns, "One... Two... Three..." or sometimes 5 turns, "One...Two... Five!  I mean Three!"  Detonation would not destroy the Holy Hand Grenade, i.e., it can be reused, however, monsters can throw it back at you, of course.

The Holy Hand Grenade would grant some intrinsics when carried, but I've yet to figure them out.  I thought maybe fire resistance, but then you could just arm it in your inventory and become a suicide bomber...so you'll have to find another source of fire resistance if you want to do that.  Maybe extrinsic telepathy and half physical damage, or drain resistance (since it's Holy?), or something along those lines.  I'm open to suggestions.

The quest nemesis would be The Killer Rabbit of Caerbanno, base monster would be a rabbit.  It would be fast, or maybe very fast.  Would have stoning resistance and maybe some other resistances, but not fire.  Maybe I'll give him an extra bite attack or two, or a slim chance (5%) of his attack causing instadeath.

Thursday, March 7, 2013

code restructuring: technique

Before I talk about the restructuring of the technique code, I want to extend a big thank you to Finland, which is the source of the majority of my blog views, per capita (USA wins out in overall quantity).  In honor of your Finnish dedication, I will add a new comestible to my variant: lutefisk (please let me know if this is the wrong term in Finland).

My current thought is that it will behave similarly to royal jelly, but when eaten, will give the message: "This tastes like the worst thing you've ever tasted!"  I may change the message for the case when confused by a potion of booze, as I once read a guide to eating lutefisk online, and the first step was "get so drunk that you can't taste it."

...

Moving on, I'm almost done with restructuring the technique code.  Instead of a long switch statement, I'm using a function pointer for each technique.  This will allow for the potential of techniques having more than one effect, as the new tech struct can have a linked list of function pointers, where each function is called in serial.

For example, say we want a technique that deals cold damage and stuns the target monster, and a technique that deals fire damage and stuns the target monster.  The two techniques can share the stun code, so the first would have a linked list containing two function pointers, one to fire damage technique code, and one to stun technique code, whereas the second would have a pointer to cold damage technique code and a function pointer to the same stun code as 'fire-stun'.

Why restructure?  Part of the reason is because of shit like this:


A closer look:



This unreachable break statement appears all over tech.c.  My guess is that someone made the mistake early, when writing tech.c, then copy and pasted the mistake in several more places.  It doesn't make the game not function, but it's ugly.

With the new system I'm implementing, there could also be hybrid/random techniques that randomly select from a couple of the technique function pointers (they'd have to be compatible... combining bless and raise zombies doesn't make any sense).  These random/hybrid techniques could potentially be granted as sacrifice gifts, which would add an interesting dynamic to sacrificing.

As a next step, I'm going to take on the scroll/potions/spell effects... i.e., the type of stuff that can be broken up pretty easily.  Once again, the new structuring will allow for craziness like scrolls/potions/spells with multiple effects, etc, if I, or someone else, decides to add that in the future.

The point of all this is to make the code much more loosely coupled to make expanding and modifying the game easier.