Curses of the Sensitized Soul


“But I don’t want to go among mad people," Alice remarked.
"Oh, you can’t help that," said the Cat: "we’re all mad here. I’m mad. You’re mad."
"How do you know I’m mad?" said Alice.
"You must be," said the Cat, "or you wouldn’t have come here.”
From "Alice in Wonderland" by Lewis Carroll

I need to make a correction to something I said in a previous post about remove curse. It does a lot of things. It is by no means only useful for minstrel wrath.

I walked into Saturday evening after our staff meeting ready to rock out a quick few code changes. The plan was to modify how the sensitize and phobia spells work allowing them to be dispelled by remove curse. Little did I know...and it's the journey to effect this seemingly simple change that inspired today's quote.

The False Sense of Security

I knew a few things walking into this code task. The debuff spells were never created to wear off so they didn't have that mechanism nor did they track what they applied to a target. Both of these are easy enough to fix - no problem. I decided that I should look at how remove curse works on the technical side and my really bad misconception was suddenly shattered.

Down The Rabbit Hole

The interesting thing about curses is that they have a long and storied history in RetroMud. The frog is well known and some oldbies may remember the dark rose curse. I figured there was a basic mechanism in place to apply and remove them and that is where our story goes off the rails.

You see, what I didn't know is that as curses were added over the years coders simpy added more catch code into remove curse. The spell had to manually be made aware of any new curse spell added to the game. Design like this can become fragile very quickly as a system grows and ours is over twenty years old.

Refactoring Wonderland

I came up with a basic design - let's make all curses innately know how they are applied and how they are removed. This would let remove curse be blissfully ignorant of the details and just tell the curse to remove itself when detected. For my fellow developers out there if you instantly thought of factory style code and anonymous function pointers you'd be right.

Where do we store that information though...the best place is in on the user object. If that doesn't strike a little terror into your heart, then odds are you haven't been around for more than a few years. We've seen some spectacular failures attributable to the user object getting too big to fit into memory. Despite knowing this - I embarked on this path anyway to see what would happen.

Rita and I ran some tests on the user object and had a little bit of fun tormenting Ritatest and Kellintest before agreeing that, amazingly, the changes were working and everything looked clean.

This led me to the next bit...

Oh No, It's Poisoned!

Our joy over the stable user object was dashed quickly by the problems that popped up while refactoring the curse spells. Some of the curses used really crusty code including some poison flags that are long out of date. Knowing full well that curiosity killled the cat I ran a search across our entire codebase to find all occurrences of these old flags. It turns out that, although nothing in the mudlib and mechanics still used the flags, they were sprinkled throughout a good number of code files. We find this a lot with older conversions; most references get updated but the ones that don't are always what new coders find to copy/paste when learning LPC. I took my list of impacted files and cleaned up:

  • three rooms on Sosel
  • one piece of equipment
  • one npc on Wysoom
  • a section of the user object
  • a spell

The other fun task here was finding out that some spells are no longer part of guild configurations but they do exist in the monster guilds! Better yet - some exist in neither of those places but were added manually to various NPCs out there across the various planets!

Curse those Meddling ... Curses?

The more I worked through the old curse spells the more I realized that we'd never really codified what a curse is or related any of these spells together. The cursed flag, hilariously, didn't actually do anything to the player. The curse spells set the flag and only remove curse had ever been taught to unset it. It does clear at logout so there's no need to be paranoid about curses from ancient times coming back to haunt you once this is all resolved.

Are We There Yet?

I really wanted to post up about new functionality tonight but it's just not going to happen. There's another few evenings of work left to go. I am holding off on converting curses until such time as the staff has had enough time to unwind what curses are out there and how we want to define them from a mechanics perspective.

The mechanics work in the user object supporting curses is done and at most needs a few more tweaks. It doesn't matter that all of the curse spells aren't converted because they work as they exist today. The debuff spells can be made to work with the new system and all those old curse spells can follow along later.

This leads us right back to where we started - the debuff spells need to keep track of what's been applied to a player so remove curse can reverse it properly. All of the phobia and sensitize spells are coded individually, so, my first order of business was to create a shared core object that describe how any debuff spell works. This core object exists in our development environment and I built some layers on top of it that allowed me to eliminate duplication across all of the phobia line of spells from mage secondaries. The acidophobia and cryophobia spells have been converted and that's pretty much where I stopped for the night.

There are probably a few more days of work left and then some code review so at best this may land by the coming weekend. I realized that despite my disappointment, this is a really good example of how simple things aren't actually as simple as they seem. Hopefully you find this helpful in understanding more about what goes on behind the scenes and, as always, keep the bug reports and suggestions coming!