14 Mar, 2010, David Haley wrote in the 101st comment:
Votes: 0
I'd better switch to Wink/TCP rather than Wink/UDP, then!
14 Mar, 2010, Deimos wrote in the 102nd comment:
Votes: 0
shasarak said:
David more or less answered this one already, but basically each effect should be saving its ownstate, and not that of the PlayerCharacter. The magnitude of the effect varies with time. So, after the first tick, effect A divides base strength by 2, and effect B adds 3 to strength; after the second tick, effect A divides base strength by 4, effect B adds 6 points to it; after the third tick, effect A divides base strength by 8, while effect B adds 9 points to it; and so on. It doesn't store what the PlayerCharacter's strength is, it stores what impact it (dynamically) has on whatever value is fed into it.

Obviously the order in which the effects influence the outcome is significant (as it would have been in my original example, in fact) so you may need to add some kind of attribute onto the effect which tells the proxy which order to sort them in. If we assume for the sake of example that effect A is evaluated first, and that the character's default strength is 20, then if we ask the proxy for the character's dynamically calculated strength after each tick, the result will be:

tick 0: 20
tick 1: (20 / 2) + 3 = 13
tick 2: (20 / 4) + 6 = 11
tick 3: (20 / 8) + 9 = 12 (assuming we round to an integer).
tick 4: (20 / 16) + 12 = 13
tick 5: (20 / 32) + 15 = 16

and so on. At no point does either effect store what the state of the PlayerCharacter is, nor does it store the result of any previous calculation; it's simply that the impact of the effect itself varies over time. The impact of wearing pieces of equipment, etc. is modelled by using other effect objects (whose impact might perhaps be constant while the equipment is worn, and stop as soon as it is removed, although it doesn't have to work like that).

How you're doing it:

Tick 0: 20
Tick 1: ( 20 / 2 ) + 3 = 13
Tick 2: ( 20 / 4 ) + 6 = 11


gives you a much different result than what you described:

Tick 0: 20
Tick 1: ( 20 / 2 ) + 3 = 13
Tick 2: ( 13 / 2 ) + 3 = 9


Effects that "half your strength every tick" and "add 3 to your strength every tick" would operate like the latter (saving PC state). If you use the former, you're throwing away any intermediate states and the difference between your strength for any 2 given ticks is not what it should be according to your effect descriptions. For instance, the difference in your strength between tick 1 and tick 2 should be "half of tick 1's strength + 3", but 13 / 2 + 3 != 11, as your algorithm produces.
14 Mar, 2010, David Haley wrote in the 103rd comment:
Votes: 0
Hmm, yes, I suppose that's another very sensible way of interpreting how such an effect would work. I'm curious to know how Shasarak would handle this. It does involve storing state, because you can no longer feed the unmodified strength through the effect pipeline: you need the one modified from the last run-around…
14 Mar, 2010, flumpy wrote in the 104th comment:
Votes: 0
Some code:

class Player{
def stats
}

class ProxyStat{
def baseStats

def effects = []

def methodCalled (def name, args …){
If(name == "getStrength"){
effects.each(){ it -> it.modifyStrength(base.strength)}
}
}
}

class Effect{
def modifier = 3 // say
def modifyStrength(def str){
str - modifier
}
}
class stat{
def strength
def con
def wis
def dex
}


… Or something to that effect, correct me if I'm wrong Shas

* edit: obviously you'd need some duck type checks on that each there, but you get my drift
14 Mar, 2010, David Haley wrote in the 105th comment:
Votes: 0
What is that trying to show?
14 Mar, 2010, flumpy wrote in the 106th comment:
Votes: 0
Hmm I think I missed a few posts whilst typing mine… I was trying to demonstrate what shas was talking about at the bottom of page six! Damn this tiny keyboa :thinking:rd
14 Mar, 2010, flumpy wrote in the 107th comment:
Votes: 0
Basically, you can make the effect object an observer of any other object you like tbh so it receives messages from its surroundings. Or, pass the player object in to the modify method and never store it.

That coupled with some ordinance and convention should be flexible enough to cope with most of what you are talking about I think?

Edit: back reading a few posts again I agree this could become a little over engineered perhaps
14 Mar, 2010, David Haley wrote in the 108th comment:
Votes: 0
If I'm not mistaken, what you're getting at is something that was discussed all the back on post 55… am I missing something?
[link=post]43277[/link]
Incidentally your method isn't quite right either as an implementation of that discussion, because it still makes assumptions about the kind of things that can be affected. You would have to generalize things to get where Shasarak was proposing.

I was confused because I thought you were trying to address the more recent problems.
14 Mar, 2010, shasarak wrote in the 109th comment:
Votes: 0
Deimos said:
How you're doing it:

Tick 0: 20
Tick 1: ( 20 / 2 ) + 3 = 13
Tick 2: ( 20 / 4 ) + 6 = 11


gives you a much different result than what you described:

Tick 0: 20
Tick 1: ( 20 / 2 ) + 3 = 13
Tick 2: ( 13 / 2 ) + 3 = 9

You're talking about a rather different thing, now. :smile: Up until now we've been discussing the case where different strength-modification effects operate independently of one another - the effects of them stack, but in such a way they don't know need to know anything about where the value they're modifying is coming from: they do the same thing regardless of whether that value comes from the Character or via another Effect. You're now talking about a case where the effects have become interdependent - the impact of one effect is different depending on something that another effect did the previous tick. This is a much higher level of complexity; and yes, obviously if the impact of one effect does depend on what another effect has previously done, that information does have to be stored somewhere.

It's worth asking whether that really is what you want to do, of course. Should the effect of one strength-altering spell actually be different depending on what other strength-altering spells are active at the same time? I can think of situations where something similar to this might happen in terms of (say) simultaneously healing and poisoning - poison halves your hit-points every tick while healing restores them - but there you probably aren't talking about an effect which should perfectly reverse itself when the spell wears off: the spell that restores 3 hit points per tick probably shouldn't take them away again when it ceases to function, the healing should be permanent; ditto the damage caused by the poison; so you don't actually need a proxy-effect system at all in that case, you are just directly changing the Character's hitpoint score.

If you really do want the effect of a spell to vary depending on the action of other spells, and you want all of the effects to be reversible when it wears off, then clearly it does need to be aware of other spell effects. Off the top of my head, I would think the halving-strength spell would entirelyoverride the Character's strength handling, but the way it would do its calculation would involve it (rather than the Character's proxy) applying other strength-modifying effects and caching the result from its calculation the previous tick.
14 Mar, 2010, shasarak wrote in the 110th comment:
Votes: 0
David Haley said:
shasarak said:
Obviously the order in which the effects influence the outcome is significant (as it would have been in my original example, in fact) so you may need to add some kind of attribute onto the effect which tells the proxy which order to sort them in.

Doesn't this break encapsulation, though, because suddenly effects need to be aware of the notion of being sorted with other effects they know absolutely nothing about? :wink:

No. :smile:

That's roughly on a par with arguing that it breaks encapsulation for a character to have a publically accessible strength score because that assumes the existence of something which might conceivably ask for its strength.

It's not bad encapsulation for something to have access to data without which it would not be able to perform the functions it is designed to carry out.

David Haley said:
When you put it like that, it does sound silly. But if you think of it as plain old spells and counterspells, where counterspells are spells and can be countered, it doesn't sound as silly.

The question is whether it really makes sense to have a counter-spell that is quite as specific as that. A spell which reduces damage from fire makes sense; a spell which reduces damage from fire only in situations where another spell has already increased the fire damage in a way that is dependent on the species of its target seems a little overengineered - it strains credulity that an orc shaman would bother to come up with a spell like that when they could simply produce an anti-fire spell that would have far wider applications.
:smile:
14 Mar, 2010, Deimos wrote in the 111th comment:
Votes: 0
Yes, but what you've been discussing in terms of how to accomplish it doesn't match up with what you said you wanted to accomplish. I'm not saying that it's "wrong" to calculate the effects the way you are (certainly there are advantages, as you've pointed out), but it would be very difficult to explain to a player why the difference between his strength this tick and last tick isn't "previous strength / 2 + 3", given that that's what your effect descriptions told him that it logically should be.

Anyway, I'm intrigued by your hitpoint example. Who says attributes shouldn't function the same way? I've never seen a system that treated them as such, but doesn't it kind of make sense? When something weakens you, you don't instantly get better. You get stronger over time (regeneration), until you're back to normal. This would make the system we've been talking about much easier, and probably make for an interesting dynamic, I think.
15 Mar, 2010, David Haley wrote in the 112th comment:
Votes: 0
shasarak said:
David Haley said:
Doesn't this break encapsulation, though, because suddenly effects need to be aware of the notion of being sorted with other effects they know absolutely nothing about? :wink:

No. :smile:

That's roughly on a par with arguing that it breaks encapsulation for a character to have a publically accessible strength score because that assumes the existence of something which might conceivably ask for its strength.

It's not bad encapsulation for something to have access to data without which it would not be able to perform the functions it is designed to carry out.

It has nothing to do with adding methods so that people can call them. If you have effect sorting, suddenly effects need to know how to sort themselves with respect to other completely arbitrary effects. Or, the proxy-effect-manager-widget needs to peek inside and see how to sort them.

Your suggestion was rather hand-wavy: "let's just let them have sorting information". How exactly would you propose this work?
15 Mar, 2010, shasarak wrote in the 113th comment:
Votes: 0
shasarak said:
If you really do want the effect of a spell to vary depending on the action of other spells, and you want all of the effects to be reversible when it wears off, then clearly it does need to be aware of other spell effects. Off the top of my head, I would think the halving-strength spell would entirelyoverride the Character's strength handling, but the way it would do its calculation would involve it (rather than the Character's proxy) applying other strength-modifying effects and caching the result from its calculation the previous tick.

That last suggestion was complete b*llocks, of course. :redface: I shouldn't attempt detailed software design that late in the evening! Clearly you can't have one effect entirely overriding others of the same type, otherwise what happens if you get two of those operating at once?

Possibly a better approach would be to have a single master-effect which is the only thing directly referenced by the proxy but which invokes all currently active strength-effects itself, and (if necessary) caches the result of its having done so last time round.

It's probably worth saying as well that the situation we're dealing with is fairly nasty. If you wish to disparage my suggested system :smile: then you not only need to point out a situation in which making it work is complicated, you have to demonstrate that an alternative system is substantially better at dealing with that situation. If you suppose that we have two different magical effects, one of which halves strength every tick, while the other adds 3 strength points per tick, but that each has to reverse its effects when it wears off, how else would you handle that? If, for example, we use the approach of storing an unmodified strength number on the character and also a modified one, then suppose that the halving effect wars off after 5 ticks, and the +3 effect wears off after 7, what do you set the modified strength to at the point when the halving spell wears off, but the +3 spell is still active? Many of the points the halving spell has removed were only there in the first place because of the +3 spell, so you can't just restore all points lost.
15 Mar, 2010, shasarak wrote in the 114th comment:
Votes: 0
David Haley said:
It has nothing to do with adding methods so that people can call them. If you have effect sorting, suddenly effects need to know how to sort themselves with respect to other completely arbitrary effects. Or, the proxy-effect-manager-widget needs to peek inside and see how to sort them.

Effect objects definitely do not need to sort themselves. The proxy needs to know how to sort them.

If you're going to have a system where the impact of different effects inevitably varies depending on the order in which they are applied - e.g. in this instance because (n + 3) * 2 != (n* 2) + 3 in the general case - then at some point you need to take a decision about what order to apply them in.

How you do that is entirely a design decision. Maybe you just always apply them in order in which they were created - so if the doubling spell was cast first, then the +3 spell, you work out the total as (n * 2) + 3. If the +3 spell was cast first, then you do it the other way round. If you choose to do it that way, then the effect doesn'tneed to have any sorting attribute on it for the purposes of this example.

On the other hand you might decide, again as a design decision, that multiplying effects should always be calculated first, and additive ones afterwards; in other words, that it should always be (n * 2) + 3 and never (n + 3) * 2, regardless of which way round the spells are cast. In that case, the effects need to have some kind of tag which allows the proxy to determine which ones add and which ones multiply, and sort them accordingly. The simplest way to do that would probably be to have a set of integer values which define different levels of priority - e.g. multiplication and division might be 100, addition and subtraction might be 200 - and then have the proxy do a simple numeric sort based on that value.

There are probably going to be cases where some effects need to take precedence over other ones. For example, if you have an effect active on a banana which causes it to bend away from an orc's mouth when he tries to eat it, thus preventing it from being consumed (but which has no effect when a human eats the banana) then that might need to take precedence over other effects which make things happen when the object is successfullyeaten. Once the eat-blocker effect is triggered it needs to indicate somehow to the relevant proxy that it shouldn't go on to process other eating effects (perhaps by triggering some sort of Veto exception). For that to work, we have to make sure that the eat-blocking effect is processed before other eating effects are, which means the effect in question has to be tagged by the code as taking precedence over things that happen when the object is eaten successfully. In general, if an effect might actually prevent the action that triggers it from happening, it needs to be processed earlier than effects which result from the action being successful, so it needs to have a lower sort-value.
15 Mar, 2010, David Haley wrote in the 115th comment:
Votes: 0
Hmm, well, at least it's clear now that it's a lot harder than was initially made out to be doing completely arbitrary things inside those callbacks, because we've seen that even for something so simple as addition and multiplication we've needed to add extra complexity. Just imagine if you wanted to edit things in completely arbitrary ways beyond addition and multiplication…

Your fourth paragraph is yet another example of something where, as you code things up, you really need to be aware of the other kinds of effects that are possible, and adding new effects can require changing code for everything because suddenly new and possibly complex dependencies have been introduced even in the magic system that lets you modify anything however you like.

This was my point, really. You can't just hand-wave away these complexities saying that code can be arbitrarily modified.
15 Mar, 2010, Deimos wrote in the 116th comment:
Votes: 0
shasarak said:
Possibly a better approach would be to have a single master-effect which is the only thing directly referenced by the proxy but which invokes all currently active strength-effects itself, and (if necessary) caches the result of its having done so last time round.

Perhaps, but then you're assuming that "strength effects" are somehow categorizable as such by the proxy. What happens in the case when an effect halves strength, but also doubles intelligence? If it got called by both the strength master-effect and the intelligence master-effect, you'd end up with the wrong results. And, of course, you'd have to have a master-effect for every possible affectable(?) trait, which is, in itself, a problem.

shasarak said:
It's probably worth saying as well that the situation we're dealing with is fairly nasty. If you wish to disparage my suggested system :smile: then you not only need to point out a situation in which making it work is complicated, you have to demonstrate that an alternative system is substantially better at dealing with that situation. If you suppose that we have two different magical effects, one of which halves strength every tick, while the other adds 3 strength points per tick, but that each has to reverse its effects when it wears off, how else would you handle that? If, for example, we use the approach of storing an unmodified strength number on the character and also a modified one, then suppose that the halving effect wars off after 5 ticks, and the +3 effect wears off after 7, what do you set the modified strength to at the point when the halving spell wears off, but the +3 spell is still active? Many of the points the halving spell has removed were only there in the first place because of the +3 spell, so you can't just restore all points lost.

Yeah, I don't know. I had a big long example typed up and then I started throwing in "what if's" to see what would happen and it broke down and cried. :tongue: I don't think it's possible.
15 Mar, 2010, shasarak wrote in the 117th comment:
Votes: 0
Deimos said:
shasarak said:
Possibly a better approach would be to have a single master-effect which is the only thing directly referenced by the proxy but which invokes all currently active strength-effects itself, and (if necessary) caches the result of its having done so last time round.

Perhaps, but then you're assuming that "strength effects" are somehow categorizable as such by the proxy.

Obviously.

Deimos said:
shasarak said:
Possibly a better approach would be to have a single master-effect which is the only thing directly referenced by the proxy but which invokes all currently active strength-effects itself, and (if necessary) caches the result of its having done so last time round.

What happens in the case when an effect halves strength, but also doubles intelligence? If it got called by both the strength master-effect and the intelligence master-effect, you'd end up with the wrong results. And, of course, you'd have to have a master-effect for every possible affectable(?) trait, which is, in itself, a problem.

There's no good reason to model both of those things on the same effect object in the first place - it'll be simpler if you don't. The same spell could easily create multiple effects. But even if you insisted on putting both modifiers on the same effect object, it's still not a problem: the basic effect overrides two different methods (strength and intelligence); one of those would be called by the master intelligence effect, and the other by the master strength effect. Remember that we're not updating values on the Character, here, we're applying modifiers to the result of querying those values. The modifier applied may be dynamic and change for each tick, but checking the impact of the effect on intelligence doesn't change anything that the effect is doing to strength or vice versa - the modifier is changed as a result of tick events being detected, not as a result of the modified values being queried.

Having categories of master-effect is indeed rather annoying, but at least you could add a whole new category of effect (and effects within that category) without having to modify anything else, so the OO implications aren't too painful. I think you probably only need two-level effects like this if you need effects to be capable of being highly interdependent in the way we've recently been discussing - that is, if the impact of one effect differs, depending on the impact of others of a similar type. If what A does is in some way dependent on what B does, it's a given that something somewhere has to be aware of both A and B - there's no way round that!

In practice, most effects in actual MUDs are not interdependent in this way; different effects of the same type are simply additive. So you might have a spell that increases resistance to fire and another one that decreases it, and both could be cast on the same target; but you don't have a spell which increases fire resistance to a degree that is dependent on how much other spells have decreased it - and I'm not altogether persuaded that it would add very much to the game if you did.
15 Mar, 2010, shasarak wrote in the 118th comment:
Votes: 0
Deimos said:
Anyway, I'm intrigued by your hitpoint example. Who says attributes shouldn't function the same way? I've never seen a system that treated them as such, but doesn't it kind of make sense? When something weakens you, you don't instantly get better. You get stronger over time (regeneration), until you're back to normal. This would make the system we've been talking about much easier, and probably make for an interesting dynamic, I think.

Well, again, you're talking about several different things, there. Drinking poison might reduce strength in a way that you would gradually recover from, but if you had a magic ring which boosted intelligence at the same time as reducing strength, that's probably not something you would want the character to steadily recover from if he's still wearing the ring; plus, you can remove the ring to reverse the effect, but you can't undrink the poison. Similarly, there is a difference between restoring lost strength points and adding new ones over and above your standard total. A healing potion of some sort might restore lost strength points up to the default value; a magical cave-bear-fur cloak might boost your strength score to a higher than normal value. Those are not the same thing.

The poison and healing potion examples here should probably be accomplished by actually changing the character's strength score; the ring and cloak examples might work better using proxies and effects.
15 Mar, 2010, Deimos wrote in the 119th comment:
Votes: 0
shasarak said:
There's no good reason to model both of those things on the same effect object in the first place - it'll be simpler if you don't. The same spell could easily create multiple effects.

Well, I'll grant you that, with the caveat that such a system would be horrible to maintain. For instance, suppose I create a new spell and I want it to reduce strength by 3 every tick. Do I have a "-3 str per tick" effect that already does this? I can't just create one without finding out, or I risk redundancy. So, I have to sift through all of my effects to find out. Maybe I have one, maybe I don't. What if I change my mind later and want it to reduce strength by only 2, instead? I can't just change the effect, because other spells might rely on it. So again, I may have one or I may not, and I have to sift through all my effects and find out. And if no other spells relied on the effect that I stopped using, I now have an orphaned effect that nothing uses, but I can't possibly know that unless I sift through all possible spells, potions, etc. to find out.

shasarak said:
Well, again, you're talking about several different things, there. Drinking poison might reduce strength in a way that you would gradually recover from, but if you had a magic ring which boosted intelligence at the same time as reducing strength, that's probably not something you would want the character to steadily recover from if he's still wearing the ring;

Typically, maybe, but not probably. I was explicitly exploring the idea where that wouldn't be the case at all. Raising and lowering your max strength would function identically to raising and lowering your max hitpoints. There would be no differentiation between how it got modified, just as there isn't for hitpoints.

shasarak said:
plus, you can remove the ring to reverse the effect, but you can't undrink the poison.

Again, this would describe typical MUD behavior, but in a system like I was suggesting, when you removed the ring, your strength would regenerate back to normal, similar to how if the ring lowered your max hitpoints, it wouldn't just shoot back up to maximum when you took it off.

shasarak said:
Similarly, there is a difference between restoring lost strength points and adding new ones over and above your standard total. A healing potion of some sort might restore lost strength points up to the default value; a magical cave-bear-fur cloak might boost your strength score to a higher than normal value. Those are not the same thing.

Apples and oranges. There are items in typical MUDs that raise your maximum hitpoints. Your magical cave-bear-fur-cloak would not boost your strength - it would boost your maximum strength, and you would then begin regenerating up to that maximum, in the same fashion as hitpoints.
15 Mar, 2010, David Haley wrote in the 120th comment:
Votes: 0
Deimos said:
Well, I'll grant you that, with the caveat that such a system would be horrible to maintain. For instance, suppose I create a new spell and I want it to reduce strength by 3 every tick. Do I have a "-3 str per tick" effect that already does this? I can't just create one without finding out, or I risk redundancy. So, I have to sift through all of my effects to find out. Maybe I have one, maybe I don't. What if I change my mind later and want it to reduce strength by only 2, instead? I can't just change the effect, because other spells might rely on it. So again, I may have one or I may not, and I have to sift through all my effects and find out. And if no other spells relied on the effect that I stopped using, I now have an orphaned effect that nothing uses, but I can't possibly know that unless I sift through all possible spells, potions, etc. to find out.

Not to mention that it's that much more book-keeping to do when canceling a spell's effect, tracking which spells came from where, for purposes of attributing score etc.
100.0/159