Category Archives: Spells

Preserving Newlines in XML Serialization

With .NET’s XML serialization, it kills newlines when you serialize XML to disk. More specifically, it converts a CR+LF into just an LF (\r\n becomes just \n).

This was causing annoyances with the spell editor, since you can edit source code for spells with it, but the code would appear all on one line after saving and reloading.

The fix was to declare XmlWriterSettings with a newline preference.

The code was this:

         public void Save()
         {
             XmlSerializer serializer = new XmlSerializer(GetType());
             Stream stream = new FileStream(FileLocation.SpellDirectory + FileName,
                 FileMode.Create, FileAccess.Write, FileShare.None);
             serializer.Serialize(stream, this);
             stream.Close();
         } 

And now it’s this:

        public void Save()
        {
            XmlWriterSettings ws = new XmlWriterSettings();
            ws.NewLineHandling = NewLineHandling.Entitize;
            XmlSerializer serializer = new XmlSerializer(GetType());
            Stream stream = new FileStream(FileLocation.SpellDirectory + FileName,
                FileMode.Create, FileAccess.Write, FileShare.None);
            XmlWriter writer = XmlWriter.Create(stream, ws);
            serializer.Serialize(writer, this);
            stream.Close();
        }

I can have my newlines and eat them too. Oh joy!

A Dozen More Spells Working

These spells were made to work today:

Water Elementalist

* Blending
* Minor Blending
* Tide of the Seas
* Water Bolt
* Dispel Magic

Air Elementalist

* Coldshield

Earth Elementalist

* Dirt Cloud

Fire Elementalist

* Fireskin
* Fireshield

Paladin

* Judgement

Anti-Paladin

* Apocalypse

Cleric

* Soulshield

A Bunch of Spells

Nearly three dozen spells were made functional today:

Air Elementalist

* Airy Starshell
* Hypnotic Pattern
* Telekinesis

Cleric

* Create Water
* Detect Poison
* Group Heal
* Know Alignment
* Silence
* Turn Undead

Druid

* Analyze Balance
* Harbor of Balance
* Twilight

Earth Elementalist

* Earthen Starshell
* Earthen Tomb
* Stornogs Spheres

Fire Elementalist

* Fiery Starshell
* Group Globe

Illusionist

* Cowardice
* Demi Shadow Magic
* Dispel Invisible
* Hypnotic Pattern
* Mirage Arcana
* Mass Invisibility
* Misdirection
* Phantasmal Killer

Necromancer

* Cloak of Fear
* Heal Undead
* Protect Undead

Ranger

* Dazzle

Shaman

* Greater Ravenflight
* Greater Sustenance

Sorcerer

* Infravision
* Meteor Swarm

Water Elementalist

* Adaptation
* Watery Starshell

In addition, some immortal commands were improved to make development easier and some “to caster” spell messages that were previously not shown are now shown.

Damage type vulnerability, which had only been partially implemented, is fully functional now.

A Few Spell Fixes

I think I remembered what I was working on — spells.

Ten more spells were made functional today:

Air Elementalist

* Chill of the Windsaber
* Hurricane

Cleric

* Destroy Undead

Druid

* Sunburst
* Sunray

Illusionist

* Shadow Magic

Psionicist

* Detonate
* Neural Fragmentation

Shaman

* Greater Mending

Water Elementalist

* Tidal Wave

A Few More Spells

These spells were made to work today:

Cleric

* Dispel Evil
* Dispel Good
* Holy Word
* Unholy Word

Druid

* Gleam of Dawn
* Gleam of Dusk
* Negate Hex

Illusionist

* Magnetism

Anti-Paladin

* Stamina
* Greater Stamina

A Dazzling Array of Spell Fixes

I spent much of the day working on spells, and more than 90 of them have been made to work.

Anti-Paladin

* Fear

Sorcerer

* Sleep
* Minor Paralysis
* Faerie Fire
* Celestial Sword
* Weaken
* Melfs Acid Arrow
* Prismatic Spray
* Immolate
* Shield

Air Elementalist

* Haste
* Wall of Force
* Airy Smith
* Conjure Windsabre
* Wall of Mist

Earth Elementalist

* Wall of Stone
* Wall of Iron
* Earthquake
* Earthen Smith
* Bombard
* Disintegrate

Fire Elementalist

* Identify
* Fiery Smith
* Wall of Fire
* Wall of Sparks
* Flashfire
* Conflaguration

Water Elementalist

* Wall of Ice
* Aquatic Smith

Cleric

* Heal
* Full Heal
* Cure Light
* Cure Serious
* Cure Critical
* Mass Heal
* Create Food
* Vigorize Light
* Vigorize Serious
* Vigorize Critical
* Preserve
* Blindness
* Remove Poison
* Summon
* Cure Blindness
* Cure Disease
* Curse
* Remove Curse
* Continual Light
* Darkness
* True Seeing
* Power Word Blind

Druid

* Barkskin
* Create Spring
* Nourishment
* Lesser Herbal Remedy
* Herbal Remedy
* Soothe Wound
* Moonwell
* Lightning Curtain
* Poison
* Creeping Doom
* Faerie Fog
* Purify

Ranger

* Blur

Shaman

* Lesser Mending
* Mending
* Spirit Ward
* Wellness
* Sustenance
* Etherportal
* Ravenflight
* Pythonsting
* Greater Pythonsting
* Greater Spirit Sight
* Purify Spirit
* Spirit Armor
* Greater Spirit Ward
* Earthen Grasp

Illusionist

* Illusion of Prowess
* Illusion of Incompetence
* Illusionary Wall
* Mirror Image
* Ultra Death Ray
* Nightmares
* Shadow Monsters
* Demi Shadow Monsters
* Shades
* Shadow Shield

Psionicist

* Wormhole
* Energy Drain
* Awe

Enchanter

* Negate Luster
* Illumination

Chances are some of them aren’t perfect, so as always, let me know if you find any glitches.

More Spells Working

I spent a while pushing spell code around today. The following spells have been made to work:

Sorcerer

* Strength
* Dexterity

Cleric

* Bless
* Armor
* Vitality

Shaman

* Fire Ward
* Cold Ward
* Wolfspeed
* Hawkvision
* Pantherspeed
* Bearstrength
* Snailspeed
* Molevision
* Lionrage
* Elephantstrength
* Mousestrength
* Shrewtameness

Anti-Paladin

* Wither

Air Elementalist

* Deny Air

Earth Elementalist

* Miners Intuition
* Deny Earth
* Stoneskin
* Stonestrength

Fire Elementalist

* Deny Fire

Water Elementalist

* Deny Water

Let me know if you find anything strange about any of them.

Working on Psionicist Abilities

I spent a good part of the past week traveling from the midwest to the west coast and back (5 flights total). During airport layovers I took a look at some of Tiu’s psi reports. Since I hadn’t touched psionicist spells/abilities yet it was no surprise that most of them were pretty borked.

I made changes to these spells:
Aura Sight
Biofeedback
Combat Mind
Displacement
Energy Containment
Enhanced Strength
Flight
Inertial Barrier
Intellect Fortress
Mental Barrier

These haven’t been tested thoroughly and may not all work as intended since they were done half-distractedly in various airports (LAX and MSP mostly). No fix for mana use or cast lag yet.

The intent for all psionicist buffs is that they are self-only, don’t stack amount or duration, and you have to wait until they wear off to refresh them. If any of them don’t work that way, let me know.

As always, let me know what’s still broken.

A Pile of Bug Fixes — And Help Needed

I came up with a pretty good pile of fixes over the past day or two. Here’s the list:

* Fixed a crash bug in checking fall chance for mobs.
* Fixed a crash bug with creatures that leave no corpse (undead, elementals).
* Fixed a crash bug with decaying/disintegrating containers.
* Fixed an intermittent crash bug with removing a character from memory after they log out.
* Fixed a nasty bug where a player’s race wasn’t being saved.  This meant you would come back as a Human after logging out.  Ewww.
* Fixed a bug with memorization that prevented displaying which spells were memorized.
* Fixed a bug with memorization that caused classes to receive the wrong number of spell slots.
* Non-mana classes no longer start with mana.
* Fixed the fraglist command.
* Fixed the consent command, making groups possible.
* Fixed a problem with being able to see other players in the same room.
* Fixed message for the follow command.
* Fixed a bug with the ‘look self’ command.
* Fixed the ‘drop all’ command.
* Fixed selection of elementalist classes during character creation.
* Message added to the group all command.
* Change password from menu is working now.
* Delete self from menu is working now.
* Improved logging so we always see what caused a crash.
* Fixed disappearance of room title when brief is turned on.
* Fixed the way max hitpoint values were sent to the client.  This was causing hitpoint meters to be inaccurate for anyone without a race-modified constitution of exactly 100.
* The spells ‘sense spirit’, ‘elemental sight’, and ‘spirit sight’ are working now.

There are still a few major bugs on the table (especially that nasty death bug) and quite a lot of spells to work on, but the MUD engine itself is getting noticeably more stable, going from 1d3 hours average uptime to 2d7 hours. Of course, that is with close to no players and it’s players what finds glitches. Thank you to Potius, Zrun, Tiu, Veytre, and others who have reported issues before.

If you’d like to help a bit with testing and bugfinding, I could use it. Send me an email at my Yahoo address and I’ll set you up with an immortal-pro-tem and you can poke around and find me some more work to do. 🙂

More Spells Are Working Now

25 more spells are working today, mostly defensive beneficial sorcerer and cleric spells like ‘fly’, ‘invisibility’, and ‘protection from fire’.  There are quite a lot more to work on, but it’s good progress.

Offensive Spells

I finished up more of the new spell engine and damage spells can be used now.  I’ve only tested magic missile so far, but it worked beautifully. 😛

Changes to Affect Modifiers

Handling a skill or spell with multiple modifiers in code has always been a bit of a nuisance.  I changed that around a bit so that they work they way I want them to.

So, here’s what adding three effects looked like in code beforehand:

Affect af = new Affect( Affect.AffectType.spell, spell.Name, 12 + level / 4, Affect.Apply.intelligence, 3, Affect.AFFECT_NONE );
victim.AddAffect(af);
af.ApplyType = Affect.Apply.constitution;
af.Amount = 8;
victim.AddAffect(af);
af.ApplyType = Affect.Apply.dexterity;
af.Amount = -5;
victim.AddAffect(af);

You’ll notice that the target has 3 separate affects added just for one spell.  That’s because each affect could only handle a single modifier.

After making the modifiers into a list that can have a variable length, here’s what the same code looks like:

Affect af = new Affect( Affect.AffectType.spell, spell.Name, 12 + level / 4, Affect.Apply.intelligence, 3, Affect.AFFECT_NONE );
af.AddModifier( Affect.Apply.constitution, 8 );
af.AddModifier( Affect.Apply.dexterity, -5 );
victim.AddAffect(af);

Now it takes half as many lines of code to do the same thing and looks a lot cleaner.  The codebase also shrunk by about 300 lines of code in the process.

This also means that some spells or skills that used to show up multiple times on the score screen will only show up once.

The Spell Engine

I finally got the spell ‘plugin’ system to work as intended for the first externally-coded spell.

Each spell is stored in an XML file outside the MUD engine, i.e “Fireball.xml”.  The file has a bunch of settings for the spell like casting time, target type, modifers, etc.  It also has an optional code section for more complex spells.

Yesterday I got the simple case working, that of a single-effect spell with no custom code like detect magic.  It just sets the ‘can detect magic’ ability on the target for a number of game hours.

Today I got the more complex case working — that of a spell that uses compiled custom code.  The example spell is ‘minor creation’.  It has a lot of custom code to process keywords and select predefined objects based on those.

The code I put together a year ago almost half-worked.  It could load the spell code from the file and compile it, but when it came time to execute it failed.  Turns out that most of the issue was how namespaces were being referenced and how types were being created — lots of detailed C# reflection stuff.

Now that I’ve worked that out there are no more roadblocks to ‘modernizing’ spells.  Sure, only 2 are converted so far and there are 419 to go, but now that the groundwork is in place it shouldn’t be too difficult.

So far this is only on my local machine – not up on the server yet, but will be within a day or two.

Continuing Spell Migration

When we last saw our hero, he was working on migrating spells from being hard-coded in 15 different places to being individual XML data files that are loaded at boot time.

While this makes it easy to modify, enable, disable, rename, or adjust spells without a recompile, the main reason I’m doing so is because there’s just so dang much clutter in the codebase with spell info strewn about everywhere.  It’s like a pack of wizards exploded in there, I swear.

This will also make it far easier to make minor adjustments for balance.  Instead of having to track down a developer to go through many slow tweak-recompile-reboot cycles just to adjust spell damage, the “balance engineer” will be able to work independently.  In the future it may be possible to perform online editing of spell attributes without a reload.  This is obviously not something that everyone should be allowed to do.

Part of the migration will be to move most of the actual function code into the spell files.  Most spells are pretty generic in nature — add an affect (flight, strength, poison) or affect hitpoints in some way (fireball, heal).  Even so, the same ~10 lines of code are duplicated for pretty much every spell with only the name changed.

Making the spells somewhat independent of the game engine also makes the engine less “tied” to Basternae.  At some point I’d like to create a space-based MUD using the same code, and the spells would obviously be dead weight.

A Whole New Spell And Skill Engine

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.