ID:142659
 
Code:
effects
var
list/contents
proc
get_bonus(var/stat)
var/list/changes = list()
var/bonus = 0
for(var/effect/effect in src.contents)
var/list/ch = effect.get_change(stat)
if(ch!=0)
changes.Add(ch)
var/list/colliding = list()
var/list/types = list()
for(var/count=1;count<changes.len;count+=4)
if(!changes[count] in types)
types.Add(changes[count]=types.len+1)
colliding += list()
else
var/list/pl = colliding[types.Find(changes[count])]
pl.Add(changes.Copy(count,count+4))
changes.Cut(count,count+4)
for(var/count=1;count<colliding.len;count++)
var/max
var/min
var/list/pl = colliding.Copy(count,count+1)
for(var/sc=1;sc<pl.len;sc+=4)
if(pl[sc+1]>0)
if(!max)
max = sc
else
if(pl[max+1]<pl[sc+1])
max = sc
else
if(!min)
min = sc
else
if(pl[min+1]>pl[sc+1])
min = sc
if(max)
changes.Add(pl.Copy(max,max+4))
if(min)
changes.Add(pl.Copy(min,min+4))
for(var/count=1;count<changes.len;count+=4)
bonus += changes[count+1]
return bonus
effect
proc
get_change(var/stat)
var/list/ret = list()
for(var/count=1;src.vars.Find("effect_[count]"),count++)
if(src.vars["effect_[count]"]==stat)
ret.Add(src,src.vars["effect_[count]_type"],src.vars["effect_[count]_magnitude"],src.vars["effect_[count]_source"])
return ret


Problem description:

This is way too complicated, and I can't seem to think up a better way to handle it. Anybody got any suggestions?

Spell effects of the same type/source that modify the same stat will only take effect if they are the strongest effect of the group, however, opposites will take effect at the same time.

FOr instance, a strength bonus of 6 from a magic item will override a strength bonus of 4 from another magic item using the same variety of magic. However, a strength bonus of 6 from arcane magic will stack with a strength bonus of 2 from divine magic, making the total bonus 8.

On the other hand, two arcane spells that give a strength bonus of 2 and a strength bonus of -2 will take effect at the same time, and give a total bonus of 0.

...Anybody got a better way of handling this?
Okay, it turns out I just needed to sober up a bit and have a meal before attempting to recode this patch of my game.

effects
var
list/contents
proc
get_skill_bonus(var/skill)
var/list/changes = list()
var/bonus = 0
for(var/effect/skill/effect in src.contents)
if(effect.skill==skill)
var/override = 0
for(var/effect/skill/vs in changes)
if(effect.etype==vs.etype)
if(effect.magnitude<0&&vs.magnitude<0)
if(effect.magnitude<vs.magnitude)
changes -= vs
else
override = 1
break
else if(effect.magnitude>0&&vs.magnitude>0)
if(effect.magnitude>vs.magnitude)
changes -= vs
else
override = 1
break
bonus -= vs.magnitude
if(!override)
changes += effect
bonus += effect.magnitude
return bonus
effect
var
cause
owner
etype
skill
var
skill
magnitude


This was a much more elegant solution. Of course, there are probably CLEANER ways of handling this, but I'm trying to make the engine really flexible.

I'm attempting to create an engine similar to a scripting engine called Lua.

I'm creating an event/hook based architecture. The game itself is turn based, so I can do a LOT of calculations every round without having to worry about the speed hit.

The complexity of the engine itself is limited only by the rules I intend to implement. Since the game loads spells, effects, and skills using a format similar to XML, I can pretty much swap out large portions of the game without having to touch the code. Although, a lot of things cannot be changed.

For instance, I've got specific effects such as confusion, diseases, etc. And spells, like Wish, and other spells that don't have a set pattern at each cast, that makes it impossible to make an engine enough to have completely dynamic content. However, most of the simple spells, like damage spells, healing, and buffs, should be completely controlled in a general way, allowing for players to create their own spells, etc.

This is a must for a D&D-based roguelike, in my opinion.
In response to Ter13 (#1)
buff
var
// different stat-mod amounts of the same type
list/amounts = list()
New(amount)
bonus(amount)
proc
/*
* call bonus(num) to append num bonuses (amounts)
* call bonus() (no args) to return calculated bonus
*/

bonus(amount)
if(amount != null)
amounts.add(amount)
else
var
posBonus = 0
negBonus = 0
for(var/index in amounts)
if(index < negBonus)
negBonus = index
if(index > posBonus)
posBonus = index
return posBonus + negBonus

mob
// bonuses is assossiated, 2D list with bonuses["stat"]["type"] = buff-object
var/list/bonuses[][]

proc
addBuff(type, stat, amount)
var/buff/buff = bonuses[type][stat]
if(buff)
buff.bonus(amount)
else
buff = new /buff(amount)
bonuses[type][stat] = buff
// ex: getBonus("str") is going to get total calculated strength bonus from all bonus-types added together
getBonus(stat)
var/bonus = 0
var/buff/buff
for(var/types in bonuses[stat])
buff = bonuses[stat][types]
bonus += buff.bonus()

I'd do something of that nature. I don't use Byond a lot anymore, so I can't say that I just did that perfect, but that's the basic idea of my approach.
In response to Loduwijk (#2)
I like that approach. It's really convenient. Unfortunately, I think my second method is still more desirable for me. I don't care for the two-dimensional list approach as much. While it may involve less processing, this game has the possibility of literally hundreds of monsters active at any given time, being a turn-based roguelike.

I've already revamped my method again, using a much more efficient and event-hook driven approach.

I'm doing all of my skill calculations every time there is a stat/skill effect taking place. Instead of worrying about calculating the skill every time I make a skill roll.

So long as I don't forget to call a recalc() proc when I write a bit of code changing a stat or skill, there is ZERO chance for inaccuracy, while my prior methods actually prevented inaccuracy by calculating the result upon need.