• Advertisement

Archived

This topic is now archived and is closed to further replies.

Thoughts on spell "stacking" in an RPG

This topic is 5903 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''m looking for a good way to handle spell stacking in an RPG environment. Let me explain what I mean (for those that may not know). Let''s say the player has 2 spells available. First is a +20 to AC spell, and the second one is +10 AC, +20 HP, and levitation. The effect I''m trying to create is one where the player can cast them both on himself and have the effects blend together, so he gets the 20AC from the first one, and the 20 HP/Levitation from the second one. My question is, how is a good way to handle this in code? I''m working in a multi-player Cooperative RPG environment (not MMORPG), but something you could play with friends over a network. My thought is, the structure that contains the player''s data should have elements to track current buff/debuff status of every stat that can be changed by magic. Then as each spell is cast, it checks the stat it''s changing and sees if something else has already changed that stat. Might work, but I''m looking for a better way. Plus, if a player has a curse on him that changes a stat, I may not want any spells to be able to change that stat until the curse wears off. Anyone have any thoughts on this?

Share this post


Link to post
Share on other sites
Advertisement
Interesting idea, as for implementing it may be kind of tough. But here is what i think...
...you could have states that would define the spells. You can pass this into some function that checks for spell mixing, the spell mixing function could then check bool variables to see if they are on or off. Then if you have more then one on, you can handle the code that way, by changing the stats.
SImple, dont know if that was what you were lookin for, but hopefully it helps, later-


what we do in life... echoes in eternity...

Share this post


Link to post
Share on other sites
I would guess that first you''d have to have some kind of list for a spell to see what it could or couldn''t stack with. Iterate through the current list of buffs/debuffs on a person to see if the spell can stack. A curse would work the same as a buff in this case.

Breakaway Games

Share this post


Link to post
Share on other sites
It sounds like you''ve already got a perfectly good solution in mind. Basically just keep a list of buffable stats. The list contains the current modification to the base stat. When a new buff is cast lookup the stat(s) it effects and adjust the modifier to be the the max of the old modifier and the new one.

"regular" debuffs could be a seperate entry in the list. So the final stat would be base+buff-debuff.

Curses could be handled by having a negative value in the buff slot and checking for that before adjusting the modifier.

-Mike

Share this post


Link to post
Share on other sites
Thanks for the info. Haven''t played many muds. Anyone got a good example of some effects that stack like I''m looking for?

Share this post


Link to post
Share on other sites
Most MUD code is broken with regards to the 'affects' - hence the 'fixchar' command to restore the characters after the affects have broken them So I wouldn't recommend copying that stuff. It also doesn't do what OldRod asks, as the affects stack cumulatively.

I suggest you just store the spell effects in a list. The effects would be a load of attribute:modifier pairs, saying which attribute is modified and by how much. Now, when you call Player.GetAC() for example, this function takes your base AC, and then iterates through the spell effect list, totalling up any modifiers to AC as it goes. If you want the effects of some spells to override the effects of others, rather than be cumulative, you do this in the function that applies the spell to the character, by checking if there is already a modifier to the given stat, and if so, checking to see which spell takes precedence (removing the old effect if it should be replaced). This is simple enough to implement, and assuming you're not gonna have that many spells on you at any one time, this will usually be efficient enough.

Now, if you want cumulative spell effects (eg. where your example would have yielded 30 bonus AC points rather than 20) then it's easiest to just use a parallel set of 'modified stats' as already suggested and return (normal_stat + modified_stat) when the value is requested.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]

Edited by - Kylotan on February 25, 2002 3:18:03 PM

Share this post


Link to post
Share on other sites
quote:
Original post by Kylotan
Most MUD code is broken with regards to the ''affects'' - hence the ''fixchar'' command to restore the characters after the affects have broken them So I wouldn''t recommend copying that stuff. It also doesn''t do what OldRod asks, as the affects as the affects stack cumulatively.



Well, we used to treat the affects as a queue of function objects hanging off each of the character''s stats, so there was no need for a fixchar. The topmost object would cache the value so that you don''t have 15 function evaluations each time, only when the queue is altered. Ok, the affects did stack, but the architecture is flexible enough that you can change that by writing the appropriate functions in the function objects.

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny
Well, we used to treat the affects as a queue of function objects hanging off each of the character''s stats, so there was no need for a fixchar. The topmost object would cache the value so that you don''t have 15 function evaluations each time, only when the queue is altered. Ok, the affects did stack, but the architecture is flexible enough that you can change that by writing the appropriate functions in the function objects.

Your system sounds a lot better than the code available in freely available MUD source. I was going to mention caching above, but I felt that overcomplicated the issue - after all, the speed hit in this part of the code is unlikely to be that big.

Ass you probably know, most MUDs out there just apply ''affects'' by adding their value to the player''s current stat. This goes haywire if the stat is altered through some other means, especially if there is some sort of floor or ceiling. (Example: my Strength is 20. Cast a Strength spell, giving me +6 making it currently 26. However, the system limits me to 25. Then, whe the spell wears off, its effect is applied in reverse (eg. subtract 6 points) and I''m down to 19 - broken system.

This is why I don''t recommend basing your code on existing freely available code.



[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost ]

Share this post


Link to post
Share on other sites
Ok, coding from memoy because I unfortunately do not have a backup (or maybe an old one somewhere). So be kind to my code A spell or similar effect would create pointers to derived affect classes and apply them to the relevant attributes, then remove them when deleted. The code I''ve posted here has flaws but that''s about what I remember from it.

  
template<class T>
class Affect // Base Affect class for stats of type T;

{
public:
virtual ~Affect() = 0;
virtual T& ApplyTo( T& stat ) = 0;
}

template<class T>
class Attribute // Class for stats of type T

{
friend class Affect<T>;
typedef Affect<T> aff_t;
typedef std::list<aff_t*> afflist_t;
private:
T base_stat;
afflis_t affs;
mutable bool cached;
mutable T cached_stat;
public:
Attribute( const T& stat )
: base_stat( stat ), cached( false )
{}

const T& () const { return base_stat; }
void Base( const T& stat )
{
base_stat = stat;
cached = false;
}

const T& Stat() const
{
Refresh();
return cached_stat;
}

void Refresh() const
{
if ( !cached )
{
cached_stat = base_stat;
afflist_t::iterator itor;
for( itor = affs.begin(); itor != affs.end(); ++itor )
(*itor)->ApplyTo( cached_stat )
cached = true;
}
}

void AddAffect( aff_t* affect )
{
affs.push_back( affect );
cached = false;
// lazy refresh

}

void DelAffect( aff_t* affect )
{
affs.remove( affect );
cached = false;
}
}

Share this post


Link to post
Share on other sites

  • Advertisement