Tuesday, May 1, 2018

goto considered awesome

Some people consider goto harmful.  I don't.

Most arguments I hear for why goto is bad have to do with code readability or that goto is inherently hack-ish.  My response would be that those issues are due to the programmer, not the goto.  I can write difficult to read hacks without using goto.  If there are other reasons to not use goto, please feel free to comment on this post.


First, I will start with a statement.  If you think goto's should not be used, then get rid of your continue, break, and return statements too.  Also get rid of switch, though the 1989 C standard oddly leaves that out (while also noting that "A switch statement casues control to jump...")


3.6.6 Jump statements

Syntax

          jump-statement:
                  goto  identifier ;
                  continue ;
                  break ;
                  return  expression<opt> ;


I'm not sure if there's a term for using goto for error handling in C.  Maybe "error unraveling", "error unrolling", "function unwinding"?

From the Linux kernel coding style documentation (Documentation/process/coding-style.rst):
Albeit deprecated by some people, the equivalent of the goto statement is
used frequently by compilers in form of the unconditional jump instruction.


The goto statement comes in handy when a function exits from multiple
locations and some common work such as cleanup has to be done.  If there is no
cleanup needed then just return directly.

The rationale for using gotos is:

- unconditional statements are easier to understand and follow
- nesting is reduced
- errors by not updating individual exit points when making
  modifications are prevented
- saves the compiler work to optimize redundant code away ;)


Okay, so the first three rationales are good and the last is bonus for compiler writers I guess.  (The nice thing about compiler writers, though, is that deep down inside, they know that regular programmers know more than they do).

Thursday, September 22, 2016

Wounding

So, I've implemented the new WOUNDING feature for slashem and included a new chaotic artifact long sword named Nightblood (taken from some book).  The patch is for SlashTHEM.

The gist is that if you "wound" a monster, it will continue to take damage until you kill it or until it bleeds out.  Just apply this patch and add #define WOUNDING to includ/config.h and you should be good to go.

greg@viper:~/src/SlashTHEM$ git diff 
diff --git a/include/artilist.h b/include/artilist.h
index 172a20f..522a74b 100644
--- a/include/artilist.h
+++ b/include/artilist.h
@@ -28,6 +28,9 @@ static const char *artifact_names[] = {
 #define     ELEC(a,b)    {0,AD_ELEC,a,b}        /* electrical shock */
 #define     STUN(a,b)    {0,AD_STUN,a,b}        /* magical attack */
 #define     ACID(a,b)    {0,AD_ACID,a,b}
+#ifdef WOUNDING
+#define     WOUN(a,b)   {0,AD_WOUN,a,b}
+#endif

 STATIC_OVL NEARDATA struct artifact artilist[] = {
 #endif    /* MAKEDEFS_C */
@@ -355,7 +358,11 @@ A("Cat's Claw",        DAGGER,
     (SPFX_RESTR|SPFX_DCLAS), 0, S_RODENT,
     PHYS(5,7),    NO_DFNS,    NO_CARY,    0, A_NEUTRAL, NON_PM, NON_PM, 1000L ),
 #endif /* NEWHON_ARTIFACTS */
-
+#ifdef WOUNDING
+A("Nightblood", LONG_SWORD,
+  (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), 0, 0,
+  WOUN(5, 10), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, NON_PM, 4000L),
+#endif
 #ifdef TOURIST
 A("Whisperfeet",               SPEED_BOOTS,
     (SPFX_RESTR|SPFX_STLTH|SPFX_LUCK), 0, 0,
@@ -898,6 +905,9 @@ A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L )
 #undef    FIRE
 #undef    ELEC
 #undef    STUN
+#ifdef WOUNDING
+#undef  WOUN
+#endif /* WOUNDING */
 #endif

 /*artilist.h*/
diff --git a/include/attk.h b/include/attk.h
index a52a9ce..9f11570 100644
--- a/include/attk.h
+++ b/include/attk.h
@@ -141,7 +141,12 @@ extern char *attk_dname(Attk);
 #define AD_POLY        43    /* RJ -- polymorphs (genetic engineer) */
 #define AD_CORR        44    /* corrode armor (black pudding) */
 #define AD_TCKL        45    /* Tickle (Nightgaunts) */
-#define AD_ENDS        46    /* placeholder */
+#ifdef WOUNDING
+  #define AD_WOUN   46  /* Wounding attack */
+  #define AD_ENDS   47    /* placeholder */
+#else
+  #define AD_ENDS   46  /* placeholder */
+#endif

 #define AD_CLRC        240        /* random clerical spell */
 #define AD_SPEL        241        /* random magic spell */
diff --git a/include/config.h b/include/config.h
index 1655897..1febcf7 100644
--- a/include/config.h
+++ b/include/config.h
@@ -435,6 +435,10 @@ typedef unsigned char    uchar;
 #define WALLET_O_P      /* Perseus' Wallet, and all related code (tsanth@iname.com)*/
 #define LIGHTSABERS
 #define JEDI
+
+/* Wounding and Nightblood features */
+#define WOUNDING
+
 #define NWAR
 #define CONVICT        /* Convict player with heavy iron ball */
 #ifdef LIGHTSABERS
diff --git a/include/monattk.h b/include/monattk.h
index fd440cd..5ca8414 100644
--- a/include/monattk.h
+++ b/include/monattk.h
@@ -90,7 +90,12 @@
 #define AD_DARK        48    /* acts similar to cursed scroll of light, making an area unlit */
 #define AD_WTHR        49    /* withers items */
 #define AD_LUCK        50    /* reduces luck */
-#define AD_ENDS        51    /* placeholder */
+#ifdef WOUNDING
+  #define AD_WOUN     51
+  #define AD_ENDS     52
+#else
+  #define AD_ENDS        51    /* placeholder */
+#endif

 #define AD_CLRC        240    /* random clerical spell */
 #define AD_SPEL        241    /* random magic spell */
diff --git a/include/monst.h b/include/monst.h
index 86ac201..68fb06c 100644
--- a/include/monst.h
+++ b/include/monst.h
@@ -139,6 +139,9 @@ struct monst {
     long mlstmv;        /* for catching up with lost time */
 #ifndef GOLDOBJ
     long mgold;
+#endif
+#ifdef WOUNDING
+    long wounding;
 #endif
     struct obj *minvent;

diff --git a/src/artifact.c b/src/artifact.c
index 69b0add..d37b396 100644
--- a/src/artifact.c
+++ b/src/artifact.c
@@ -1281,6 +1281,18 @@ int dieroll; /* needed for Magicbane and vorpal blades */
         return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
     }

+#ifdef WOUNDING
+    if (attacks(AD_WOUN, otmp)) {
+        if (realizes_damage) {
+            if (rnd(5)==1) {
+                mdef->wounding += rnd(10);
+                pline_The("sharp blade wounds %s.", hittee);
+            }
+        }
+        return realizes_damage;
+    }
+#endif
+
     if (!spec_dbon_applies && !spec_ability(otmp, SPFX_BEHEAD) ||
         !special_applies) {
         /* since damage bonus didn't apply, nothing more to do;
diff --git a/src/mon.c b/src/mon.c
index 1bb6a87..36c2fa2 100644
--- a/src/mon.c
+++ b/src/mon.c
@@ -808,6 +808,18 @@ mcalcdistress()
     struct monst *mtmp;

     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+
+#ifdef WOUNDING
+    if (mtmp->wounding) {
+        mtmp->mhp -= rnd(mtmp->wounding);
+        if (mtmp->mhp < 1) {
+            pline_The("%s dies from its wounds.", Monnam(mtmp));
+            mon_xkilled(mtmp, NULL, AD_WOUN);
+        } else {
+            pline_The("%s suffers from its wounds.", Monnam(mtmp));
+        }
+    }
+#endif
     if (DEADMONSTER(mtmp)) continue;

     /* must check non-moving monsters once/turn in case
diff --git a/src/monmove.c b/src/monmove.c
index a6d1d32..ec22bf8 100644
--- a/src/monmove.c
+++ b/src/monmove.c
@@ -858,6 +858,19 @@ register int after;
         if(i == 1) return(0);    /* still in trap, so didn't move */
     }

+#ifdef WOUNDING
+    if (mtmp->wounding) {
+        mtmp->mhp -= rnd(mtmp->wounding);
+        if (mtmp->mhp < 1) {
+            pline_The("%s dies from its wounds.", Monnam(mtmp));
+            return 2;
+        } else {
+            pline_The("%s suffers from its wounds.", Monnam(mtmp));
+            return 1;
+        }
+    }
+#endif
+
     ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */

     if (mtmp->meating) {

Tuesday, September 20, 2016

"Just a fleshwound."

I'm working on a patch for slashem (tends to be the version of nethack I tinker with the most) to add a weapon feature called "Wounding".  Basically, when you hit a monster with a weapon that has the "wounding" feature, there's a chance you will create—you guessed it—a wound.  A wounded monster will take a random amount of extra damage every turn regardless of whether its hit.




What good is wounding without a nice artifact to carry out the message?  I've added Nightblood, a chaotic long sword that can wound.



I still need to test this to make sure it all works, at which point, I'll make the patch available.  Also, I think it's important to mention how much I love CPP.  I'm not talking about C++, but the C Pre-Processor.  All languages should have one.

Thursday, September 15, 2016

Starting to get back into it

I was looking through the Slashem, and then SlashTHEM code, pondering adding some new artifacts, when I decided to do something nice and fix all the indentation problems in the code.  A lot of the issues stem from mixing of Tabs and Spaces.  I personally prefer spaces since tab-sizes can be changed depending on the text editor you're using, so I changed all tabs to spaces.  Whatever your preference, tabs or spaces, I think we can all agree they shouldn't be mixed.

Fortunately, this who process was as simple as running indent -nut -kr on all the source files.  I discovered this very old, simple tool when working for a company that used the GNU indentation style, which if you're not familiar with it, is a steaming pile of horse shit that should never have been invented (Thanks Stallman!).

You can clone the SlashTHEM git repository here: https://github.com/Soviet5lo/SlashTHEM

Then just download and apply my patch to fix all the indentation to use indentation of four spaces per indentation level: https://drive.google.com/open?id=0B7oiSGh7Lg0lWEJKVmRwQzlHN0E

Enjoy.

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.