Archive for April, 2008

Removing Items From A Container In A Foreach Loop

Wednesday, April 23rd, 2008

It wouldn’t have been unrealistic for the designers of .NET to find a way to make this work:

foreach( Item i in ItemList )
{
  if( i.ShouldBeRemoved )
  {
    ItemList.Remove(i);
  }
}

What happens is you get a ‘collection modified’ exception and you’re hosed. You can’t move to the next item in the list because removing the item broke the list. It wouldn’t have been that hard for the design of IEnumerable (the thingy that makes foreach possible) to keep track of where the next item was even after a removal.

Instead of being able to use the above code, something like this clunky bit is required:

for( int i = (ItemList.Count - 1); i >= 0; i– )
{
  if( i.ShouldBeRemoved )
  {
    ItemList.Remove(i);
  }
}

It’s like telling someone they can avoid head-on car collisions by always driving in reverse.

Anyhow, there was a bit of a problem with the Select() command and socket management, and this was the solution. The socket code is now functional and stable enough that I can log in and run around trying to play the game. It’s not terribly playable yet — I have a *LOT* more work to do, but it’s still theoretically possible that a development server could go up i mid-but-more-likely-late May.

Sorting The Easy Way

Tuesday, April 22nd, 2008

If you have a list of objects, say List<Widget> it’s mighty easy to to sort them using .NET.

First, derive the Widget class from IComparable:

public class Widget : IComparable

Then create the CompareTo method. In this case, we’re sorting the list of Widgets by name:

public int CompareTo(object obj)
{
  if( !(obj is SynthProfile ))
  {
    return 0; // We could throw an exception here if we wanted to.
  }
  return this.Name.CompareTo(((SynthProfile)obj).Name);
}

Once that’s done all you have to do is call:

WidgetList.Sort();

Easy.

Raph Koster Is Pretty Awesome

Saturday, April 19th, 2008

Some of you may remember Raph from Ultima Online, Star Wars Galaxies, or Everquest II. He also wrote a few articles for Imaginary Realities webzine (a webzine about MUDs for those of you who don’t know). The site was pretty active from 1998-2001, but at some point it vanished from the face of the Earth.

Well, Raph was nice enough to give permission to reprint his IR articles on FindMUD. They’re a good read, and still relevant today, so if you’re at all interested in MUD design you should read ‘em over.

Raph’s blog is also pretty interesting and updated fairly regularly. It’s worth becoming a regular reader.

300 MUDs on FindMUD

Friday, April 18th, 2008

Data entry is a lot of work and it takes a lot of time. Even so, I’ve been making steady progress on FindMUD. It’s up to 300 MUD listings now.

Our next goal is to pass MudMagic, which has just over 500 listings. It won’t be blazingly fast, but it will happen.

Command Processing Engine Complete

Thursday, April 17th, 2008

I completed the last of the code for the command processing engine today. Not much detail to report — it’s done and seems to work well enough.

A New Command Processing Engine

Wednesday, April 16th, 2008

Command processing in the old Basternae was pretty klunky. The command interpreter would just pass on any text that was entered and each command function would have to do a lot of parsing to split up the command strings and figure out what the user actually intended. About half of each command would be devoted just to breaking up strings in some cases.

Luckily with .Net we have all these nice string functions — Split, Join, Substring, IndexOf, Remove, and many more.

With the new command processing engine I’ve just written the command functions are a lot easier to read, maintain, and create more of.

Of course, I’ve had to redo every command in the process and that’s only 80% done so far, but it’s a far better system overall.

And, of course, I still have to finish the replacement spell system.

Automatic Line Wrap

Sunday, April 13th, 2008

When writing a zone, it can be tough to know where to end your lines of text.

While a standard terminal has 80 characters, some telnet programs start to look weird with any line that is more than 77 characters, and some terminals have 130 or more characters per line (usually depends on screen resolution).

With different zone writers writing descriptions with varying line lengths it can make the MUD look pretty inconsistent from zone to zone.

That’s why I wrote an auto-wrapping function that takes care of all of that.  It will take a description and insert line breaks as necessary.  Right now it just defaults to a 78-character terminal width, but it will be user-configurable when I’m done with it.

This means that zone writers don’t have to worry about line breaks anymore.  They can just type out their descriptions and it’ll be handled by the MUD.

Word wrapping still isn’t perfect, so I’ll need to work on that a little, but it’s pretty neat to have autowrapping in place now.

A Whole New Spell And Skill Engine

Saturday, April 12th, 2008

Well, maybe not a *whole* engine quite yet, but certainly two thirds of one.

I’ve generated about 500 little XML files to hold all of the skill and spell data for dynamic runtime loading.  It’s all pretty neat — skills and spells can be tweaked by hand without having to compile any code (though the MUD requires a reboot) and they’re loaded at runtime, stored in a Dictionary type, and accessed based on their names.

There isn’t a single hard-coded spell or skill value in the engine.  Hardcoded values were something that always bothered me.

Another thing I did in this process is embed “logical preference” data in the skill and spell files so that the AI engine can be improved while at the same time removing the need for thousands of lines of “spaghetti code” like in Basternae 2.  You see, each spell and skill check in B2 was hardcoded in a specific order and with a specific percentage chance.  Adding a skill or rearranging mob AI meant editing these in more than one place.

Instead (when the AI code is done), we’ll be able to set a few flags on each spell or skill and it will handle it automatically (unless a specific mob has a personality override file).

Oversimplified example:

Fireball.xml:  Type = offensive, Preference = 65, Likelihood = 40
LightningBolt.xml:  Type = offensive, Preference = 50, Likelihood = 50

This means, essentially, that a mob would have a 40% chance of casting fireball during combat, and if that didn’t go off, it would have a 50% chance of casting lightning bolt.  Changing the way the mob performs in combat is just a simple number tweak.

I have some pretty huge plans for mob AI, but this new spell/skill system goes a long way toward making those plans easy to implement.

I also have yet to embed all necessary custom code in the spell/skill files, but one thing that’ll be done is that most information needed to trigger a spell will be embedded in the file.  Instead of manually writing a dozen lines of the same code for each spell to validate the target, check saving throws, set damage type and amount, send messages, and deliver the affect(s), most spells will use one general-purpose function that checks the spell types and flags and executes the spell’s action.

This means that most standard spells that are just damage or single-affect, like “soulshield” or “fireball” won’t have any embedded code at all.  Instead, only super-involved custom spells like the enchantment spell “earthen smith” will have their own embedded instructions.

Well, that was long-winded.  It had to be — I’ve done a lot and I’m pretty proud of what I’ve accomplished with this.

Learned Something New Today

Friday, April 11th, 2008

I came across this article on Scripting with C#.

Quick summary: It tells how to load and compile C# code from within a running application so that you can dynamically load scripts.

This is something I’ve been meaning to find out how to do for a while. I’ve always wanted to create a file-based spell system that loads and compiles all spells at boot time so that they aren’t so tightly integrated into the engine. As it was historically, if you removed a single hardcoded spell, such as “armor”, the entire mud would crash or at least be very unhappy.

Well, what good are 400+ hardcoded spells going to do you when you use the mud engine for a sci-fi, historical fiction, or contemporary post-apocalyptic setting? None at all. That’s why getting them once-removed from the core is something I wanted to do. Super-long-term there’s not just one MUD coming out of all this effort.

Technology Always Fails

Thursday, April 10th, 2008

There’s only so many times I can see a message like:

“Error loading operating system”

Before it starts to get frustrating.

Won’t be much progress today.  I love computers.