[Scrymud] [gingon at WANfear.com: new spell code]

Justin Piper kat_skan at mailandnews.com
Thu Jan 31 18:51:37 PST 2002


The Spell interface looks good to me, but for some of these member
functions I don't think the default implementation is sane, and I'm kind
of worried about those global instances of Spell classes.

int Spell::getSpellTarget(int, const String*, critter&)
   All completed spells should override this method to find the
   appropriate target.  This should be a pure virtual function to ensure
   that a spell that doesn't implement this won't compile.

void Spell::doSpellEffects()
void Spell::doWearOffEffects()
void Spell::doMovementEffects()
void Spell::doPerTickEffects()
   I think you're going to need a critter& argument to
   doMovementEffects() for it to be very useful.  That spell event
   somehow needs to know who did the actual moving in most cases.  Even
   if the spell only does anything when the critter it was cast on
   moves, you'll still need a way to tell if it was the victim or
   someone else in the room who did the actual moving.

   I'm Not 100% sure that not overriding these is really a problem
   worthy of a note in the log, except perhaps at the DEBUG log level.
   As it stands, I think you'll just end up with tons of junk in the log
   complaining that Orb of Power doesn't have its own implementation of
   doThisEffect and doTheOtherEffect.

   Also, would doDispelEffects perhaps be a better name for doWearOffEffects?

void Spell::doFailureCanned()
   Same deal here as before, spamming the log needlessly.  I do think
   this method should call the general doFailure() method, since 99.999%
   of spells are likely to fail the same when cast by a mob as when cast
   by an object.  Speaking of which, I don't see a general doFailure().
   Oh, and unless you can think of a reason that anything other than a
   child of the Spell cast would ever need to call the doFailure*()
   methods, they should probably be protected access.

void Spell::setupSpell(int, int, char*, char*, char*, char*, char[])
   This method seems very strange to me.  Why bother with this at all?
   Couldn't the args for this be private static consts in the concrete
   classes?  This method also necessitates those global instances of
   each spell class, which seems kind of clumsy, imo.  I'll have more to
   say on those later, though.

void MobSpell::onCast(int, const String*, critter&, int, int)
void ObjSpell::onCast(int, const String*, critter&, int, int)
void DoorSpell::onCast(int, const String*, critter&, int, int)
void RoomSpell::onCast(int, const String*, critter&, int, int)
void SelfSpell::onCast(int, const String*, critter&, int, int)
   Hmm... The way you've done things, I think you can actually put all
   of these into a Spell::onCast().  Since getSpellTarget() updates a
   member variable and returns a success/failure flag, Spell::onCast()
   should be able to just blindly call member functions without ever
   knowing specificly what getSpellTarget found.  In the event that this
   isn't flexible enough, onCast() can still be overridden.

SpellSpearOfDarkness spellSpearOfDarkness
SpellOrbOfPower spellOrbOfPower
SpellHolyWord spellHolyWord
   Okay, unless there's some specific reasoning behind these that I'm
   not seeing, I think this is a bad idea.  For starters, the spell
   target is a member variable of these classes, which means
   doWearOffEffects and doPerTickEffects flat out break if two people
   ever cast the same spell!
   
   Here's my suggestion.  Write a SpellFactory class with a method like
   this:

      Spell* getSpell(String spellName, critter& caster,
                      int i_th, String* vict)

   The getSpell method should check the critter's know spells and, if
   the critter knows a spell named spellName, it should return a new
   instance of the appropriate concrete class, otherwise it should
   return NULL.  Then, change the cast() method in commands.cc so that
   it calls SpellFactory::getSpell(), and, if the result is non-null,
   calls the Spell's onCast() method.

   Doing it this way, you cut way back on the number of things that
   cast() needs to know to work.  onCast() doesn't need all those
   parameters, they can be moved to Spell::Spell() instead.  You also
   open up the way for stateful spells.  For example, a protection spell
   that affords a calculated amount of benefit, perhaps based on level,
   can properly undo its actions even if the target's level changes. The
   only problem is that you need to destroy the Spell object when it
   wears off, but that's not really a big deal, since you have to remove
   it from the affected_by list of the victim already, anyway.  I don't
   think there will be a significant memory overhead, since you can make
   a lot of those member variables (msg_lost_con, actions, diversions,
   etc) static const and share them between all instances of the class.

Anyway, the only other thing I have to say is that this might be a good
time to look at how the spells are divided up among the source files.
It seems to me like things would be easiest to manage if all the base
Spell classes were in one file, then have each concrete spell in a file
named after itself.  You'd get quite a few files when you were all said
and done, but they could all be regulated to a ./Spells directory to
keep things tidy.

--
"Picture the sun as the origin of two intersecting 6-dimensional
hyperplanes from which we can deduce a certain transformational
sequence which gives us the terminal velocity of a rubber duck ..."

On 29 Jan 2002, Edward Roper wrote:

> ----- Forwarded message from gingon at WANfear.com -----
> From: gingon at WANfear.com
> To: eroper at WANfear.com
> Subject: new spell code
> Date: Mon, 28 Jan 2002 06:31:07 -0800 (PST)
> User-Agent: IMP/PHP IMAP webmail program 2.2.3
> 
> rewriting the spell code to eliminate redundant code, and generally make it 
> work better all around. all spells will be derived from the Spell class (though 
> usually not directly). should make coding new spells alot easier.  take a look 
> at it and tell me what you think: http://www.gingon.org/spells.h
> 
> --Gingon




More information about the ScryMUD mailing list