Archive for the 'Uncategorized' Category

The Idea Evolution of Basternae: Technical

Tuesday, June 19th, 2007

Over the past few days I’ve spent a while working on rewriting the Basternae source code in C# (even though the original code is not completely object-oriented yet).  Ideally I’d like to have it run as a standalone application linked to a SQL server for data storage.  This is doable in C++, but in C# it’s far easier.

I still have the C++ version, but after some experimentation it looks like I’m going to stick with the idea of migrating to C#.  It’s been my favorite language lately, and it offers a bit more power than C++ does.  What better way to fully master a language than port a 115k-line project to it?  I will still have the old code to fall back on, but I hope to have the new code working in less than a month (which is the timeframe I had planned for the original string conversion anyway).

For now I’m pretty sure that I’m going to stick to C++ for the client, especially since it’s already written and just needs some slight modifications to work with the new engine and to work with Linux (ideally it will be able to run on Linux, Windows, and MacOS, but I have no access to MacOS so that’s a “maybe eventually” thing) .

As a techie I usually focus on the tech stuff first, but sometime soonish I’ll probably be posting about the gameplay changes I have in mind.

Inheritance = A Good Thing

Wednesday, June 13th, 2007

No, I didn’t just have some rich relative kick off and leave my name in the will.  The closest I have to a rich relative is an uncle who can afford to buy a new pair of shoes every two years.

In the original MUD code and in most C-based codebases I’ve seen, mobs have one set of data and players have a similar but different set of data.  They all have things like hitpoints and movement points, but mobs have things like AI scripts and behavior flags while players have extra things like skill values and guild memberships.

There are two ways to handle this in C:  either have completely different sets of data for each, or have a core set of data and a pointer to the extended data depending on which type it is (player or mob).  The first way is sloppy and dangerous, while the second is sort of a “poor man’s inheritance”.

I’ve rewritten this to use parent and derived classes and all of a sudden some things that were very hard to do are incredibly easy.  It’s also become incredibly easy to have things work differently for mobs and players by being able to use overridden functions for the player versions of code.

For example, since mobs don’t have skill training, almost every check for something like a bash or headbutt is based on a combination of that mob’s level and racial statistics.  For players the check uses skill values modified by actual attributes like dexterity and strength.

Instead of writing a huge function riddled with lots of “if” statements, I can now just write different versions for each.  The code is cleaner, easier to write, and automatically smart enough to “do the right thing”.

I love C++.  Even though I’m getting a bit addicted to C# lately, it still rocks.

I never could have made this change without massive use search-and-replace, since the way to access most of the data members of players has changed completely.  I did not want to change 2000 data references by hand.

Goodbye Mobprogs

Tuesday, June 5th, 2007

Mobprogs - a neat idea, but mostly useless.

The idea was to have a scripting language that could be used to write actions and triggers for mobs and objects that would give them a little more life.  They weren’t ever used much, and I think I may have been the only one to write one.  At least, I only see the ones I wrote on the old backups I have.

The code, unused as it is, has been lying around and hindering development efforts because it’s not much but more files that have to be modified every time a major change is made.

Today I’ve finally dropped them.

I’m pondering the idea of setting up Python scripting, even though I know it’ll likely not be used by anyone except maybe me.  It wouldn’t be for anything other than to figure out how to do it, but it would probably be fun.

Even Higher Warning Levels

Tuesday, May 29th, 2007

When compiling code in MS Visual Studio .Net I always turn warning levels up to 4 (/W4).  I’ll end up getting some warnings about things I don’t care about, such as converting an int to true or false when it’s something I did on purpose or not referencing a formal parameter of a function, but it’s still better for spotting potential problems.

For example, one warning that many people often ignore but can be a big problem is “C4706: assignment within conditional expression”.  It’s the difference between:

if( ( x = a ) )
{
do something;
}

int x = a;
if( ( x ) )
{
do something;
}

Both pieces of code do the same thing: Set the variable X equal to A and then check whether X is nonzero.  The problem with the first piece is that someone reading your code has no idea whether you meant to assign A to X or check whether X is equal to A.  Even worse, one small typo and you could be doing assignment when you meant comparison.  It’s better to break it into two statements like the second piece of code so you and everyone else knows what you intended to do AND that it actually happens the way you intend.

When compiling using g++ on Linux, I’ve always used -Wall.  Since around 1995 I’ve been using that thinking it would warn me about everything it saw.  There are a few things that Visual Studio would warn me about that g++ wouldn’t catch and the more it happened the more I started to wonder why.  Cue the documentation.

AHA! While browsing the commandline parameter list for the GNU compiler, I found two interesting switches: -Wextra and -pedantic.

If you use those two switches, you’ll get what Visual Studio gave you and more.  Much more.  The bad news: I’m doing far too many ‘deprecated string conversions’.  The good news: I’ve spotted even more potential problems and can fix them before they become big problems.

Some people think warnings are just annoyances.  It’s a better idea to treat them as run-time errors.  It might be more of a pain in the butt when writing code, but it’ll help in the long run.   Thank your nitpicky compiler, it’s trying to protect you.

It’s amazing what you can do when you read the documentation…

WinMerge

Friday, May 25th, 2007

One of my biggest complaints when booting into Linux is that I don’t have access to a merge tool quite as nice as WinMerge. The current version of WinMerge doesn’t run under Wine, but apparently an older version, 2.0.2, will.

Some things are optional when writing code, but a good merge tool is not one of them. WinMerge is the perfect example of what a merge tool should be.

The Meld diff viewer is the best merge tool that I’ve seen on Linux, but it’s just a bit less usable than WinMerge.

The Road To C++

Friday, May 18th, 2007

I’ve gradually been changing more pieces of code from C to C++.  As each piece goes from being a random function dangling somewhere to a piece of a coherent class the code begins to make a little more sense.

So many bits and pieces are going to benefit from being private data members.  In a lot of cases there were hoops that had to be jumped through to handle values properly.  Race, for instance.  If a character was polymorphed into another race, some of the functions in the game would react to the new race and others would react as if nothing had happened, so a troll turned into a lizard might still lumber into the room.

With the ability to make some data members private, we can make it so that nobody can look at player->race, but instead have to call player->GetRace() which will be smart enough to check for polymorph.  The same can be said for checking or adjusting ability scores, hitpoints, and all sorts of things that can be modified by spells.

It’s a phenomenally massive undertaking, but with the proper amounts of time and insanity it can be done right.

Hammering and Tinkering

Saturday, May 12th, 2007

I’ve been ripping and tearing a bit more and there have been quite a few internal changes:

  • Much of the use of char * has been replaced with std::string, which is a bit more powerful and somewhat safer.
  • Almost all of the shared string routines are no longer being used and the shared string manager will be removed soon.  This means that the MUD will take up more memory, but will ultimately end up being more stable and less prone to “string weirdness”, segfaults, etc.  The shared string manager was a fine idea in 1996 when the typical desktop system was a Pentium 1 running at somewhere between 60 and 150 MHz and would typically have about 16-32MB of RAM.  In fact, most MUD codebases were designed to run well on a slowish 486 PC (i.e. 486DX-33).  I remember Illustrium Arcana, the first MUD I worked on, being SUPER SUPER FAST on a Cyrix 6×86 200MHz processor with 32MB of RAM.
  • Many of the “new” and “free” routines that were used in the C code have been converted to constructors and destructors.  This is good because we don’t have to worry whether a creation or destruction routine is called on a mob, object, room, etc.  The initialization and deinitialization how happens automagically.
  • Two zones have been connected and are loading - the Thri-Kreen hometown Thannik’Tzil and the Kobold Village, both written by me.
  • I’ve been exchanging emails with Thendar and she has granted permission to use all of her zones - Plateau, L’strizzen, Ice Palace, Gypsy Quest, Court of the Muse, and a few others.

It’s still just running on my home PC and is far from stable (I still have quite a lot of major changes to make too), but it is gradually coming together to look like something.

And It Begins

Wednesday, May 9th, 2007

I’ve been working with the old Magma 3.0 codebase for almost a week now.  Things I’ve done so far:

  • Removed all of the old outdated OS-specific code (Sequent, Apollo, Amiga).
  • Removed all instances of sprintf (a very dangerous function prone to buffer overflows).  These have been replaced with snprintf, which is safer.  Over 1000 functions have been replaced.
  • Converted all major structs to classes (a C to C++ conversion).
  • Broken the single monolithic merc.h header file into many different header files in order to make the code easier to maintain.

I’m also working on removing or replacing most of the old predecessor code and adding support for just about every area format I can find.  When this is all over it will be a full codebase rewrite in C++.

The goal is to build an engine that is easily extended and modified, with OLC, easy-to-add mods and scripts, and plenty of ways to add fun things to the game without it being too unstable.  Original Magma was incredibly unstable because it was built in a hurry — the codebase was based on reverse-engineering the format of existing areas for Basternae 1.  There was very little testing at first and it took years for the engine to fully develop into a robust form.

It may take a few years for this new engine to develop into a fully robust form, too, but this programmer knows a vast amount more than he did eight years ago when building Basternae 2 was begun.