15 Mar, 2010, Runter wrote in the 141st comment:
Votes: 0
David Haley said:
Do you need a simple majority, two-thirds majority or merely two people before you believe something? :rolleyes: Well anyhow, I'm glad this particular confusion is behind us. Let's go back to discussing how arbitrarily we want to modify things without any limits whatsoever and without knowing ahead of time what we want to do. :wink:

Less facetiously, your suggestion might not sit will with Shasarak, because to implement your proposal one needs to know an awful lot again about what one can modify, which is exactly what he has been trying to avoid. So your suggestion would sit well in my camp, but really doesn't address Shasarak's goals here. I'm still curious to know how he'd handle all this in practice.


My opinions are also democratically elected.
15 Mar, 2010, donky wrote in the 142nd comment:
Votes: 0
David Haley said:
Do you need a simple majority, two-thirds majority or merely two people before you believe something? :rolleyes: Well anyhow, I'm glad this particular confusion is behind us. Let's go back to discussing how arbitrarily we want to modify things without any limits whatsoever and without knowing ahead of time what we want to do. :wink:

Right, lesson learned. When the topic that started somewhere completely different has strayed to an exact subject, do not interject with related subjects because David will start posting helpful notes pointing that out. Can we have a vote to determine whether I can believe this opinion? Or are we having one on whether Runter really believes his first?
15 Mar, 2010, David Haley wrote in the 143rd comment:
Votes: 0
Hey dude. No need to act like that. You were being somewhat snarky here from the beginning, or at least very rapidly, and by your own admission you only skimmed over most of the posts. No need to point the finger at me, either, because Deimos was also trying to indicate to you that we were talking about a different problem.
15 Mar, 2010, Runter wrote in the 144th comment:
Votes: 0
donky said:
David Haley said:
Do you need a simple majority, two-thirds majority or merely two people before you believe something? :rolleyes: Well anyhow, I'm glad this particular confusion is behind us. Let's go back to discussing how arbitrarily we want to modify things without any limits whatsoever and without knowing ahead of time what we want to do. :wink:

Right, lesson learned. When the topic that started somewhere completely different has strayed to an exact subject, do not interject with related subjects because David will start posting helpful notes pointing that out. Can we have a vote to determine whether I can believe this opinion? Or are we having one on whether Runter really believes his first?


Vote4lock
15 Mar, 2010, donky wrote in the 145th comment:
Votes: 0
David Haley said:
Hey dude. No need to act like that. You were being somewhat snarky here from the beginning, or at least very rapidly, and by your own admission you only skimmed over most of the posts. No need to point the finger at me, either, because Deimos was also trying to indicate to you that we were talking about a different problem.

I did not say I skimmed most of the posts. Yet you read into what I posted that this was the case. My point was that I had read through the thread. You choose to concentrate on the negative possibilities.

Deimos on reading my comment on how I did not share the problems he described, assumed that there was a way in which my system worked and proceeded to respond based on that. Not understanding his assumption, I gave vague answers up to the point where he asked questions which were related to how the system actually worked. My posts were related to the subject at hand, complex effect systems. That you and Deimos choose to get distracted on assumptions is not my problem, you can let my post pass like a ship in the night. The work I have done involves "effects that depend on other effects to derive their values over time" to quote Deimos. I don't have to post a treatise about it. I can make tangential comments.

Almost every post you have made to this thread in response to my posts, have been to try and point out how my posts are unrelated to the exact subject at hand. Why does this matter? Are tangential comments not allowed to be interjected in a thread, even if they are actually not tangential?
15 Mar, 2010, David Haley wrote in the 146th comment:
Votes: 0
donky said:
Almost every post you have made to this thread in response to my posts, have been to try and point out how my posts are unrelated to the exact subject at hand. Why does this matter? Are tangential comments not allowed to be interjected in a thread, even if they are actually not tangential?

Because there was useless confusion after Deimos asked "How does allowing more than one input parameter solve the problem of only being able to model a finite set of behaviors?". Tangential comments are certainly welcome. But tangential comments if you start playing some bizarre blame game about who's making which assumptions first are not really welcome, IMHO. It's hardly surprising that we would make assumptions about some comment given that we've been discussing it for pages and yet you're blaming all of these issues on us making assumptions unsatisfactory to you. I have an idea: why don't we write several posts blaming you for making assumptions about what we're interested in? Wouldn't that be a lot of fun too? I look forward to it already.

To be clear, I have no issue with your tangential comments. I have an issue with you getting snarky, defensive and upset that we thought you were discussing what we were discussing until your tangent. It's like you're trying to force your tangent upon our discussion, and getting upset when we try to return to our discussion. Your tangent is not uninteresting, but when it was understood that it was indeed a tangent, there was no need to start laying blame on people for misunderstanding you. You could have just said: "Yeah, ok, it was a tangent. Wanna talk about it?" You did not need to get into this strange blame game.
15 Mar, 2010, Deimos wrote in the 147th comment:
Votes: 0
It's not that they are tangential. I don't really mind that, given that most of what's being discussed in this thread has started as tangential at some point or another (I mean, what does any of this have to do with programming languages anyway?).

What I don't like is this attitude of "I'm only going to answer direct, specific questions and nothing more." This isn't the best medium for Q&A. It's simply too frustrating for that kind of back and forth banter. We come here to share elaborate ideas, descriptions, and examples that, more often than not, take a lot of time to construct.

Now, you claim to have solved some of the problems we were discussing (whether they're tangential or not), and I'd personally like to know how. If you don't want to explain yourself and help us (me) to understand how exactly you solved them, that's certainly your prerogative, but it isn't going to help anything or anyone for us to continue down this path without that clarification.
15 Mar, 2010, shasarak wrote in the 148th comment:
Votes: 0
Deimos said:
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.

You're thinking like a C++ programmer. :smile:

Depending on how much late-binding you are comfortable with, you could have as little as one Effect class that handles absolutely every effect in the game. Instead of hard-coding an Effect subclass which achieves each effect, you simply intialise it with a block from the source spell or item, and that block is evaluated by the proxy to determine what the effect does.

(I'm using the word "block" in its Smalltalk sense, here - I can't for the moment remember what the Ruby equivalent is called; the equivalent in C# would be an anoymous delegate).

So, your initialisation code in the #wornBy: method of a magic ring (using Smalltalk syntax) might be:

wornBy: wearer

| strengthEffect intelligenceEffect |

super wornBy: wearer.

strengthEffect := Effect new.
strengthEffect
overrides: #strength;
effectBlock: [:baseValue | baseValue - 3];
duration: 5.
wearer addEffect: strengthEffect.

intelligenceEffect := Effect new.
intelligenceEffect
overrides: #intelligence;
effectBlock: [:baseValue | baseValue + 3];
duration: 5.
wearer addEffect: intelligenceEffect.

wearer, of course, is a reference to the character's proxy wrapper.

You might actually want to have a dedicated Effect subclass for effects whose modification calculation is more complex, but there's certainly no need for it in a simple case like this one.
15 Mar, 2010, donky wrote in the 149th comment:
Votes: 0
David Haley said:
To be clear, I have no issue with your tangential comments. I have an issue with you getting snarky, defensive and upset that we thought you were discussing what we were discussing until your tangent. It's like you're trying to force your tangent upon our discussion, and getting upset when we try to return to our discussion. Your tangent is not uninteresting, but when it was understood that it was indeed a tangent, there was no need to start laying blame on people for misunderstanding you. You could have just said: "Yeah, ok, it was a tangent. Wanna talk about it?" You did not need to get into this strange blame game.

I wasn't looking to assign blame, I was just looking for a clear understanding of what you thought the situation was, and this is it.
15 Mar, 2010, shasarak wrote in the 150th comment:
Votes: 0
David Haley said:
Less facetiously, your suggestion might not sit will with Shasarak, because to implement your proposal one needs to know an awful lot again about what one can modify, which is exactly what he has been trying to avoid. So your suggestion would sit well in my camp, but really doesn't address Shasarak's goals here. I'm still curious to know how he'd handle all this in practice.

I don't feel I have a sufficiently good understanding of what donky is suggesting to be able to comment, really. If he would like to help me out by elaborating somewhat, I will try to produce an intelligent response; but I am not demanding that he do so.
:smile:
15 Mar, 2010, donky wrote in the 151st comment:
Votes: 0
Deimos said:
It's not that they are tangential. I don't really mind that, given that most of what's being discussed in this thread has started as tangential at some point or another (I mean, what does any of this have to do with programming languages anyway?).

What I don't like is this attitude of "I'm only going to answer direct, specific questions and nothing more." This isn't the best medium for Q&A. It's simply too frustrating for that kind of back and forth banter. We come here to share elaborate ideas, descriptions, and examples that, more often than not, take a lot of time to construct.

What I didn't say, is that this system is in use in a commercial game and I signed an NDA while working on it. So while it isn't necessarily wrong for me to go into detail about it, if I reveal bits as asked specifically about them, then it is easier for me to limit and carefully consider what I disclose.

Deimos said:
Now, you claim to have solved some of the problems we were discussing (whether they're tangential or not), and I'd personally like to know how. If you don't want to explain yourself and help us (me) to understand how exactly you solved them, that's certainly your prerogative, but it isn't going to help anything or anyone for us to continue down this path without that clarification.

I am happy to give you clarification, but you're going to have to get it out of me question by question, in the same manner you did before. Although whether you consider it worth your time and effort, is another matter.
15 Mar, 2010, David Haley wrote in the 152nd comment:
Votes: 0
donky said:
What I didn't say, is that this system is in use in a commercial game and I signed an NDA while working on it. So while it isn't necessarily wrong for me to go into detail about it, if I reveal bits as asked specifically about them, then it is easier for me to limit and carefully consider what I disclose.

Well, that's certainly useful information to know about why you were responding the way you were.
15 Mar, 2010, Deimos wrote in the 153rd comment:
Votes: 0
shasarak said:
You're thinking like a C++ programmer. :smile:

Hah! Am I really that transparent?

shasarak said:
Depending on how much late-binding you are comfortable with, you could have as little as one Effect class that handles absolutely every effect in the game. Instead of hard-coding an Effect subclass which achieves each effect, you simply intialise it with a block from the source spell or item, and that block is evaluated by the proxy to determine what the effect does.

(I'm using the word "block" in its Smalltalk sense, here - I can't for the moment remember what the Ruby equivalent is called; the equivalent in C# would be an anoymous delegate).

Hrm. Well, I don't necessarily have a problem with late binding, but it would seem that this kind of system would (could) produce repeated code blocks all across your spells/items/whatever, and break encapsulation by having an effect block tied to its source like that. Still, I like it more than any other method so far. Also, I think the Ruby equivalent is also called a block. I only read about them in passing, though, so I could be wrong.
15 Mar, 2010, Runter wrote in the 154th comment:
Votes: 0
Quote
I can't for the moment remember what the Ruby equivalent is called


It's also called block.
16 Mar, 2010, donky wrote in the 155th comment:
Votes: 0
shasarak said:
David Haley said:
Less facetiously, your suggestion might not sit will with Shasarak, because to implement your proposal one needs to know an awful lot again about what one can modify, which is exactly what he has been trying to avoid. So your suggestion would sit well in my camp, but really doesn't address Shasarak's goals here. I'm still curious to know how he'd handle all this in practice.

I don't feel I have a sufficiently good understanding of what donky is suggesting to be able to comment, really. If he would like to help me out by elaborating somewhat, I will try to produce an intelligent response; but I am not demanding that he do so.
:smile:

I will try and describe it without describing the actual implementation of the existing system in too much detail. But given how many times I have tried to do this so far, it looks like I am going to have to give some degree of insight into implementation.

As I have said, it is data-driven. Everything is referred to in terms of abstraction, by ID. An expression uses attributes from given entities (the actor, the entity the effect is authored on, the target of the action, ..), and applies them to attributes from other entities. It is possible to say, is this attribute on this object currently being used in the calculation of something? And if it is, to cascade changes in that attribute, to anything that is dependent on it. And attributes may be more than just simple values, for instance you might not need to increase the character's "hp" attribute, the "hp" would instead be defined as a type of 'curve'. Whenever its value is queried, the value at the current position of the curve for the current time is returned. If the value changes, perhaps an amount of damage applied, then the curve is recalculated. A curve might be defined by a rate of change and a maximum value, but not with the actual values for these things. Rather, with what attributes to lookup values for. In this way, almost anything can be modified by anything else, simply because only attributes have values, and everything else works in terms of attributes. Stacking is defined on a per-attribute basis as well, so anything can modify any attribute within a reachable scope, but how the attribute is modified is up to that attribute. Additionally, you do not go to the instance of a class to get attribute values, you go to a generic decoupled handler which encompasses all this state and behaviour. In fact, you can do away with classes and instances for both specific effects, item types and more.

Now a concrete case, to hopefully give some context. If a player has a sword in their inventory, then this is an item of type sword located in the player's character. The sword type would a swing action associated with it, this would be linked to a swing effect. An effect defines how expressions are applied by items. It would define how many times the expressions are applied, and how long each application lasts. So for a sword, you would swing and it would by default have a "how many" of 1 and perhaps a "how long" of 1 tick. But it wouldn't have these values on the effect, it would lookup attributes on the item the expression was operating on behalf of (in this case the sword). Then the swing expression attached to the effect would check if the swing hit (referring to attributes providing values used in the calculation), and if it did it would apply damage (referring to attributes providing values used in the calculation).

Any of these attributes used at the effect level, or the expression level, can be modified within reason by almost anything else. Maybe the wielder of the sword has modifiers from his sword wielding skill. Maybe he also has a per-tick decrease to one or more of them from a cursed potion he just drank. Maybe his opponent is so fierce that anyone they engage who has heard of them, gets a percentage decrease to a range of attributes.

Now, this is a general description of the heart of the system I worked on. I have left out a range of particulars about how exactly it worked, so it also contains flexibilities which I have not described. But this system handles multiple concurrent effects being applied to something, when each of those effects is being effected by other effects and so forth. You can have periodic decreases or increases working together on an attribute with other effects having different effects. And it does not need to be coupled to code, you don't need to limit or shape your effect system to fit how you can make classes or use inheritance, or whatever the limitations of the programming language you might be using are. This system could be implemented in any language, in much the same way.

And the advantage of being data-driven is that you have the ability to introspect and manipulate that data. Want to see what effects are not attached to any item type? This is a simple SQL query. Want to see what expressions are not used by any effects? This is a simple SQL query. Want to see what attributes are not being used at all? This is a simple SQL query. You can generate reports for these things. Much more interesting is just being able to drill down through the data. What item types are attached to effects that are marked as offensive? What are the different things that use this attribute? What are the range of values for this attribute on this subset of types? Edit the attribute values with a grid to make it easier to get an idea of how balanced things are. Something wrong with the data? Run a query to fix it up. Is the handler running a little slow? Add code generation.
16 Mar, 2010, shasarak wrote in the 156th comment:
Votes: 0
Deimos said:
shasarak said:
Depending on how much late-binding you are comfortable with, you could have as little as one Effect class that handles absolutely every effect in the game. Instead of hard-coding an Effect subclass which achieves each effect, you simply intialise it with a block from the source spell or item, and that block is evaluated by the proxy to determine what the effect does.

(I'm using the word "block" in its Smalltalk sense, here - I can't for the moment remember what the Ruby equivalent is called; the equivalent in C# would be an anoymous delegate).

Hrm. Well, I don't necessarily have a problem with late binding, but it would seem that this kind of system would (could) produce repeated code blocks all across your spells/items/whatever, and break encapsulation by having an effect block tied to its source like that. Still, I like it more than any other method so far. Also, I think the Ruby equivalent is also called a block. I only read about them in passing, though, so I could be wrong.

There's no obvious need for repetition. If the same class of spell is cast twice and thus creates two different effects, each of which is initialised using a block, that block is defined only once (within the class definition of the spell), so each effect ends up with a reference to what is actually the same block object (albeit potentially with a different execution context). If two or more related spells pass the same block to an effect, the block could perhaps be returned from a method defined on something that is a common superclass to both spell classes.

In cases where you want to do something a little more complicated, it might make sense to have some of the effect logic defined on an Effect subclass; but the logic could easily involve parameters that can be set differently on different instances of the same effect class.

Suppose we have an effect which boosts a character's strength by an amount equal to a percentage of his intelligence. We could define the #strength method on the effect like this:

strength: baseStrength

^baseStrength + (self effectTarget intelligence * self effectPercentage / 100)

You might then instantiate the effect in question like this:

castOn: target

| strengthEffect |

strengthEffect := StrengthIntelligenceLinkage new.
strengthEffect effectPercentage: 50.
target addEffect: strengthEffect
So here we've got an effect which is hard-coded to connect strength to intelligence, but by a configurable amount. (Note that the effect's effectTarget property is set by the proxy as part of the addEffect: process).

Alternatively, you could inline absolutely everything. Go back to the generic Effect which takes a block as its action:

castOn: target

| strengthEffect |

strengthEffect := Effect new.
strengthEffect overrides: #strength.
strengthEffect action:
[:baseStrength | baseStrength + (target intelligence * 0.5)]
Here you'll note that the block being passed into the effect object contains a reference to the target variable - something that is in scope within the context of the spell's castOn: method, not a variable that the effect class itself is aware of. But the block executes happily because it remembers what context it was defined in.

Either one of these approaches might be equally valid - it depends how often an effect of a particular degree of specificity is used. If spells which boost strength by a percentage of intelligence are very common, differing only in magnitude, then it might make sense to have a dedicated Effect subclass for handling them; if not, it may be quicker to inline it. More complicated behavour is probably best handled by an Effect subclass with appropriate code and properties, but even then different instances of the class can have their properties initialised differently. There's no inherent need for code duplication.

There's no encapsulation issue, either. If you think about what a spell actually is, it's simply a way for a player to apply an effect to a target. In order to do that, clearly the spell has to know which effect it is supposed to apply; telling it that doesn't break encapsulation, it's information that it needs to have to do its job.
16 Mar, 2010, Deimos wrote in the 157th comment:
Votes: 0
shasarak said:
Here you'll note that the block being passed into the effect object contains a reference to the target variable - something that is in scope within the context of the spell's castOn: method, not a variable that the effect class itself is aware of. But the block executes happily because it remembers what context it was defined in.

I don't quite understand how two similar effects could override the same superclass method, though. Using the same example we've been talking about, both strength-modifying effects would need to override #strength behavior with different blocks, yes? But how would this happen? Are you planning on doing some kind of block chaining or something?

shasarak said:
If two or more related spells pass the same block to an effect, the block could perhaps be returned from a method defined on something that is a common superclass to both spell classes.

[…]

There's no encapsulation issue, either. If you think about what a spell actually is, it's simply a way for a player to apply an effect to a target. In order to do that, clearly the spell has to know which effect it is supposed to apply; telling it that doesn't break encapsulation, it's information that it needs to have to do its job.

I see what you're saying, but I was looking at effects in a much broader sense. If other things in the game (weapons, potions, special attacks, etc.) could cause the same effects as spells do (which is fairly common practice), and you're keeping these blocks in the spell classes/superclasses, then my Sword of Weakening needs to know about the StrengthReducingSpell class in order to tell the effect how to function, right?
16 Mar, 2010, Runter wrote in the 158th comment:
Votes: 0
Runter said:
Quote
I can't for the moment remember what the Ruby equivalent is called


It's also called block.


But I think the specific term in Ruby when using it like this is a closure.
16 Mar, 2010, shasarak wrote in the 159th comment:
Votes: 0
Deimos said:
I don't quite understand how two similar effects could override the same superclass method, though.

I got a little careless about my use of the word "override" there. :redface: In that specific context I was using it in the sense of a subclass implementing a method which therefore "overrides" the equivalent method on its superclass, not in the sense of an effect overriding the default method implementation on its target.

Deimos said:
Using the same example we've been talking about, both strength-modifying effects would need to override #strength behavior with different blocks, yes? But how would this happen? Are you planning on doing some kind of block chaining or something?

Well, you don't have to use blocks if you don't want to! You could have a type of Effect where what it does is defined simply as "execute your effectBlock". Or you could have a type of effect where what it does is defined in terms of one or more permanent methods on the corresponding effect class. Or you could mix and match in any way that's useful.

In the context of discussing more than one class of effect inheriting from a common superclass, we're probably talking about the effect's action being a defined method rather than a passed-in block.

Deimos said:
shasarak said:
There's no encapsulation issue, either. If you think about what a spell actually is, it's simply a way for a player to apply an effect to a target. In order to do that, clearly the spell has to know which effect it is supposed to apply; telling it that doesn't break encapsulation, it's information that it needs to have to do its job.

I see what you're saying, but I was looking at effects in a much broader sense. If other things in the game (weapons, potions, special attacks, etc.) could cause the same effects as spells do (which is fairly common practice), and you're keeping these blocks in the spell classes/superclasses, then my Sword of Weakening needs to know about the StrengthReducingSpell class in order to tell the effect how to function, right?

Well, that might be a case where it is helpful for the effect class to use a method rather than a block to determine its action. So you have a StrengthReducingEffect class, an instance of which is created and activated by both the sword and the spell. The StrengthReducingEffect would most likely have at least one property which you set on it to tell it how much to reduce strength by. Depending on how you wanted to do it, you could have different effect classes for handling immediate and per-tick reductions, or you could handle both on the same class, and give it separate immediateReduction and perTickReduction properties.
140.0/159