Ok... NOW I'm sad.


Amanita

 

Posted

Quote:
Originally Posted by Mind Forever Burning View Post
So, what I get from this fascinating discussion is:

1) It is possible to write an engine that does something with all the powers data in City of Heroes; and
2) writing an engine that does exactly what CoX does with the powers data is much more time consuming than being lax about it

Faced with the possibility of complete extinction, my 20,000ft read is that people would be pretty happy with anything even if it wasn't completely faithful to CoX's behaviors and edge cases. And yes, before Arcanaville stomps on me for it, I'm aware that many of the engine differences would lead to broken power sets and/or unbeatable combos, but then CoX itself had its share of those at launch.

That said, I've always felt that even Arcanaville's estimates were low. Maybe that's because most programmers I've met are less productive than I imagine most of the programmers in this conversation to be. It took me at least two years to do this, and that's a significantly smaller project than building a full MMO. Based on that experience my estimate for CoX would be closer to 8-10 developer-years of effort.
We were just talking about reproducing the engine's effects complexity in a reasonable manner. To do so in a way that would actually work in an MMO? It depends on who's doing the coding. I am no slouch when it comes to algorithmic efficiency (its my programming forte) but actually banging out the couple hundred thousand lines of code to make an engine? While miracles are possible, I would guestimate a full engine minus effects artwork and clients to be about two FTE years if you were starting from scratch with really good coders. If you knew exactly what you wanted to do and also had cracker jack coders, maybe half of one FTE. But the truth is everyone thinks they are cracker jack coders, and only one in ten thousand actually is. To get it done in six months would essentially require winning the lottery. Based on what I've seen, its five FTE years plus or minus four and a half FTE years.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Mind Forever Burning View Post
OK, I really should be doing other things, but my mind just started going crazy with this.

Suppose this new MMO supported user-generated creative goods: costume pieces, missions and story lines, etc. Suppose further that users could sell them to each other, and the role of the main coordinators was to provide a store for these goods, taking a cut off the top. Would such a model be sufficient to keep the game running? I don't know how to answer that, but it's a tempting answer to the problem of never-ending content in a game that has minimal direct funding for development.

There are previous models for this, such as 2nd Life, but I think CoX has an edge in that it is an actual game and not just an empty playground.
If we're talking about how I would actually conceptualize an MMO from scratch, it would be like this. That idea includes the basic idea of a content store like you describe.

In terms of things like game play and systems, I'm a believer that gameplay and systems should be designed simultaneously, with one supporting the other, and not designed completely independently. I don't believe in building the engine that can do almost anything, and then the game that uses the engine that can do almost anything. I don't think that works well myself. All these systems are, ultimately, one system.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Arcanaville View Post
Test again.
Did test with a crabspider, you're right. Great! So the question is, do we need (i.e. is there a power with) duration-limited +-X Cur effects ? (we do need one-shot Cur mods, that's not the question) But that's in the event that Cur is just a 0-100% representation of Abs in regard to Min and Max as you said in another thread. But I'm beginning to understand given your formula you wrote below that maybe in Cur are added resistible mods and in Abs the irresistible mods. Or in Cur time-restricted mods, and in Abs time-infinite (or one-shot) mods. So what is right ?

Quote:
I don't see why. An attribmod calculation engine should be able to, given a list of attribmods, determine what is going on at time t, for all t. Otherwise, as I said, its not an attribmod calculator. Its just a calculator with a lot of rows.
I agree with you, as I said, and as you could see in the code since there is no "period" field for an attribmod, it doesn't support "_oT" effects now. In that sense, I failed, but I didn't want to get into time-related (to see the "why" of that, and your question, see ** below)


Quote:
I haven't had a chance to analyze the code completely yet, but what I meant was that resistable buffs are resisted by the resistance of the target after unresistable buffs are accounted for first.
Just to be sure I understand, so what you meant was "resistable buffs are resisted only by the unresistable resistance buffs". Actually, what I implemented was "resistable resistance buffs and debuffs are resisted only by the unresistable resistance buffs" and "other resistible buffs and debuffs are resisted by the net resistance, whether by resisted or unresisted buffs and debuffs". Maybe that's not true. I think that's what is implemented on the server, but in this case any resistible resist buff is going to be resisted by itself or any other similar effect ! And I didn't see any case of powers like that, at least for damage resistance, that's why I said "don't make resistible resistance buffs" because their effect is... unpredictable.

Quote:
You're going to special case resist modifiers separate from all other modifiers?
I special cased resistible resist modifiers, yes. (I have functions for resistible modifiers and other functions for irresistible modifiers) It's already done, and it's necessary for the above to work, at least because "resistible resistance debuffs gets resisted by resistance buffs".

Quote:
You can't rely on City of Data for order of operation.
Well, mid's also order them like that, as well as in-game descriptions and real numbers, if it's of any use to you, but they may be incorrect !!! But all descriptions I can see right now order them as damage first, then debuff. Also, you order Cur and Abs aspects before resist, so even if these mods are listed, or applied, in the order of Aspects, I am right.

Quote:
But in any case, that's your explanation of the effect: I'm asking what your calculator says, not what you personally know.

I'm still not sure what you mean by "power resolution method" vs attribmod calculation. The order in which attribmod effects are computed is a necessary requirement for the attribmod engine to function properly.

You seem to be stripping all functionality out of the attribmod calculation engine except AttrValue = Min(Max[(AttrValue + [Attribmod(Abs) + Attribmod(Cur)] * (1 - Res)),AttrMin],AttrMax)
As I said, it is an attribmod calculator. It's not a power calculator, attribmods are only a part of the power effects (other beings summons, grant powers, etc), so you need this attribmod calculator to make the power calculator, and you need that last one to make the combat engine. In your own previous **words, highlighted for emphase:
Quote:
Originally Posted by Arcanaville View Post
Honestly, I recommend you to spend just a single weekend writing as much of an attribmod calculator as you can. Not even an engine, just a calculator that can be given a set of attribmods and will calculate what the attribute values are for the entity that has them for the full duration of those attribmods, moment by moment. That's like at most 1/6th of a full combat engine. If you think you can write a full combat engine in four weekends, you should be able to do this in one without missing the NFL late game.

Just try it for even one hour and see how far you get. I can only assume you are dramatically underestimating the time necessary because you have no reference to compare to.
So I did end up overtiming this "assignment" (or challenge, we are not in school anymore) since I didn't manage to do it "for the full duration of those attribmods, moment by moment", but that necessitates time-awareness, an "engine" aspect, or at least it's stupid to implement it outside an engine (or loop) because it's going to be rewriting when you have to do the engine, so I prefered to do the engine outright. In any case, I avertised "3 weekends to implement it, 3 more to optimize it" and since I optimized a bit (that's my weakness), the result of this experiment is in the gray area. But even 12 week-ends is a tad less than 3000 hours. But to your defense, these 12 week-ends are just the writing of the implementation I already thought up in my mind, and that is based on your analysis of what the server did or closely did. So in total, that is 3000 hours or even more, but most of the work is already done somewhere.

Quote:
That's not really what I was talking about at all, but in any event, that's about 1% of the work of the entire combat engine. So: assuming I'm looking at about 10 hours of work, with testing and debugging, at this rate about a thousand hours of work and you'll have something maybe close to the complete engine done.
if you're refering to your previous quote, you did say at that time that the bold+"moment by moment" part was "like at most 1/6th of a full combat engine". I do realize 1% is less than 16,67% (1/6th) but that is one hell of a margin.

But let's stop playing "that's what you said" "-No what I said", "That's not what I meant"... Someone earlier in this thread posted a link that basically said it's impossible to plan or estimate a plan effectively because there are so many unknowns, either that or you have an all-seeing eye and/or pure luck, or take excessive amounts of margin, and guess what, you and I are just trying to guesstimate the time it would take to code this. And I'm the only one to actually work to try to measure that, and you're the only one able, or at the very least the best fit, to evaluate this. You already corrected approximately 5 things I misunderstood or thought I knew, and I may have corrected myself to 3 or 4 on my own by looking at the Paragonwiki and City of Data, and Codewalker did some more. I think I did ridiculize myself quite well already, but I want more because my mind just can't stop thinking how to implement the thing. I guess it thinks it's a hero.

I think we have sufficiently derailed the thread here, in fact, it may already be overtaken. I would like to take this moment to (finally) apologize to Bill Z. Arcanaville, would you like to continue this project discussion/report/criticism in another thread, maybe in another forum ? (there is a city sunset category over at the Titan Network)



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
Did test with a crabspider, you're right. Great! So the question is, do we need (i.e. is there a power with) duration-limited +-X Cur effects ? (we do need one-shot Cur mods, that's not the question)
Mezzes, and by extension mez protection powers, are Cur effects with a limited duration. As are defense buffs, movement speed, and just about everything except for damage, come to think of it.

Cur applying as a percentage of anything seems to be a quirk of the implementation and as far as I can tell only applies for certain attrib types (damage, endurance, hitpoints). The Cur effects for defense powers certainly don't end up adding a percentage of the defense cap for that level.


 

Posted

Quote:
I think we have sufficiently derailed the thread here, in fact, it may already be overtaken. I would like to take this moment to (finally) apologize to Bill Z. Arcanaville, would you like to continue this project discussion/report/criticism in another thread, maybe in another forum ? (there is a city sunset category over at the Titan Network)
Derails are part of life! Keep it alive here.


Be well, people of CoH.

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
I think I did ridiculize myself quite well already
I would say quite the contrary. Regardless of how many issues there are with your particular implementation, I find it telling that you cared enough to spend a weekend actually writing code. And you clearly know enough about the game engine to at least follow Arcanaville's and Codewalker's corrections, which is a deeper understanding than I have, frankly.


And for a while things were cold,
They were scared down in their holes
The forest that once was green
Was colored black by those killing machines

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
Did test with a crabspider, you're right. Great! So the question is, do we need (i.e. is there a power with) duration-limited +-X Cur effects ?
All of them are. Movement buffs are sometimes Cur. Defense buffs almost always are.


Quote:
Just to be sure I understand, so what you meant was "resistable buffs are resisted only by the unresistable resistance buffs". Actually, what I implemented was "resistable resistance buffs and debuffs are resisted only by the unresistable resistance buffs" and "other resistible buffs and debuffs are resisted by the net resistance, whether by resisted or unresisted buffs and debuffs". Maybe that's not true. I think that's what is implemented on the server, but in this case any resistible resist buff is going to be resisted by itself or any other similar effect !
Yes and no. The way the server works, the engine does an unresistable pass and computes intermediate results for resistance. Then it does a resistible pass and computes all other values given the intermediate resistance. In other words, lets say you have a target with 80% resistance (to something) and it gets hit with a -30% unresistable resistance debuff and a -20% resistable resistance debuff. The game engine calculates the target's intermediate resistance based on all unresistable effects, and gets 80-30=50%. Then it calculates the effects of all resistable effects given that resistance: the -20% debuff is reduced to -10% because of the effective resistance at that moment, and the final resistance drops to 50-10 = 40%.

However, one clock later, the server starts over. It does not start with the target having 40% res or even 50% res. It starts from scratch, recomputing the target unresistable resistance: 80% - 30% = 50%, and then applying the resistable resistance (de)buffs 50% - (20% * 0.5) = 40%.

Quote:
As I said, it is an attribmod calculator. It's not a power calculator, attribmods are only a part of the power effects (other beings summons, grant powers, etc), so you need this attribmod calculator to make the power calculator, and you need that last one to make the combat engine. In your own previous **words, highlighted for emphase:
So I did end up overtiming this "assignment" (or challenge, we are not in school anymore) since I didn't manage to do it "for the full duration of those attribmods, moment by moment", but that necessitates time-awareness, an "engine" aspect, or at least it's stupid to implement it outside an engine (or loop) because it's going to be rewriting when you have to do the engine, so I prefered to do the engine outright. In any case, I avertised "3 weekends to implement it, 3 more to optimize it" and since I optimized a bit (that's my weakness), the result of this experiment is in the gray area. But even 12 week-ends is a tad less than 3000 hours. But to your defense, these 12 week-ends are just the writing of the implementation I already thought up in my mind, and that is based on your analysis of what the server did or closely did. So in total, that is 3000 hours or even more, but most of the work is already done somewhere.
Even if you punt the actual mechanics of the clocking, the code doesn't seem to even have any hooks for clocking. It applies effects in a way that makes it difficult for them to expire in random order, because the effects are entangled with resistances. You could create an expiration queue to basically apply the inverse effect upon expiration, but you have to be very careful to honor intermediate floors and ceilings when you do that. It seems very likely that this code doesn't just omit clocking, it isn't trivially extensible to being clocked.


Quote:
if you're refering to your previous quote, you did say at that time that the bold+"moment by moment" part was "like at most 1/6th of a full combat engine". I do realize 1% is less than 16,67% (1/6th) but that is one hell of a margin.
I did say that, but being able to calculate "moment by moment" is exactly what it sounds like. You don't need to implement a clock, but you should be able to state what the current attribute values are for a *given* moment. If I say "+1.2 seconds" the calculator should be able to say. But it can't, because its not just unclocked, its completely time-unaware. And a completely time-unaware scale summer is something I could do in a single afternoon: that's an extremely tiny component of the whole. Its so small I would never write it time-unaware, because of the strong possibility my code would not be extensible to a clocked environment.

The engine has to be aware of the fact that Abs modifiers are permanent, but Cur modifiers are not and have to be able to be reversed at some moment in time. It has to be aware of activation period for attribmods that have it. That's all part of the attribmod engine, and I don't see how you are rationalizing it as part of the "powers" engine. The only thing that makes any sort of sense is you're thinking of making the attribmod equivalent of micro-ops and breaking down time-dependent attribmods into micro-attribmods and clocking them outside of the micro-attribmod engine. Which is fine, except that doesn't allow you to redefine the scope of the problem to be writing the micro engine, because that eliminates the bulk of the complexity of the problem.

Quote:
Someone earlier in this thread posted a link that basically said it's impossible to plan or estimate a plan effectively because there are so many unknowns, either that or you have an all-seeing eye and/or pure luck, or take excessive amounts of margin, and guess what, you and I are just trying to guesstimate the time it would take to code this.
No one says its impossible. What is true is all non-experts think they are far better than they actually are. In fact, most of the experts tend to think they are better than they actually are also.


Quote:
And I'm the only one to actually work to try to measure that, and you're the only one able, or at the very least the best fit, to evaluate this.
That's a fair point. I'm working the next two weekends, so I'm going to try to steal some nights and write an attribmod calculation engine. My guess is that given the context we're talking about, that's about 40-50 hours of work for all except the expression engine, entity spawning, attribmod distance effects (basically, inner and outer radius), and boost templates (basically all attribmods will be assumed to be flagged to be powers not enhancements). Maybe some other little flags I'm not considering, like the set bonus ones.

Lets see how long it actually takes.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Arcanaville
Even if you punt the actual mechanics of the clocking, the code doesn't seem to even have any hooks for clocking. It applies effects in a way that makes it difficult for them to expire in random order, because the effects are entangled with resistances. You could create an expiration queue to basically apply the inverse effect upon expiration, but you have to be very careful to honor intermediate floors and ceilings when you do that. It seems very likely that this code doesn't just omit clocking, it isn't trivially extensible to being clocked.
When you apply a resistible debuff/buff, you're modifying the resistible value of the mod with (1-res) and apply this mod directly to the result... as if it was irresistible ! Right ? So you (well my code at least) fall back to this case. And what do you do to cancel an irresistible mod ? You use an irresistible mod with opposite value ? Yes ! That's what I made, well, actually set up only, in my attribmod code (you must have found funny that my functions returned a value instead of nothing, and also, applying an Effect returns an Executable instead of void). Why, do you ask ? That's the raw cancellation effect that you would need to apply if the effect had a duration. You (nearly) have the result on hand, even if the effect is of no duration (such as heal or damage), it takes nearly nothing to leave it on the stack, so I put that as the signature of the method. This was how I would have tackled the "engine" part, leave the cancellation on a stack to apply later on or upon removal of the effect.

Let's suppose you are right, you in fact do have Cur that sums the duration-based effects and Abs the others. You anyway need to have a timer on hand for each effect in order to know when to cancel them, and what amount to cancel each effect individually, or you need to reconstruct from adding all the remaining effects, which is the same amount of data but plain computationally inefficient. Something that takes as much or less space and calculation is to keep the list of "timer & cancellation value" per applying effect instance, and you don't need store each sum separately, because "Abs+(Cur-Cancellation)" is "Abs+Cur-Cancellation". So it's more effective to store the total in either Cur or Abs as the result, and apply cancellations over it.

Also, I didn't find any duration-infinite status effect, Regen, Recovery or Recharge buff or debuff. Only damage, health and endurance modification are "infinite" and "absolute" modification (or am I missing something ?). And those don't have duration-finite modification to their Value (Spectral Wound's damage gets couteracted by a heal, not negative damage). In fact, I didn't find any attribute that needs both of them.

Also, about flooring and ceilings, you may have found that in my code I have a 'val' and an 'abs_val' fields in every Aspects. That's because "getters" are reading the val that is floored&ceiled version of the abs-val that is the blunt sum of all mods, and val gets updated when the Aspect gets modified (I was supposing you had far more reads than mods, so I opted for this "caching". But that's quickly changed if the contrary is proven)

Quote:
Originally Posted by Codewalker View Post
Mezzes, and by extension mez protection powers, are Cur effects with a limited duration. As are defense buffs, movement speed, and just about everything except for damage, come to think of it.

Cur applying as a percentage of anything seems to be a quirk of the implementation and as far as I can tell only applies for certain attrib types (damage, endurance, hitpoints). The Cur effects for defense powers certainly don't end up adding a percentage of the defense cap for that level.
Quote:
Originally Posted by Arcanaville View Post
All of them are. Movement buffs are sometimes Cur. Defense buffs almost always are.
We may be mixing "percentage" with "percents" here, see how this fits: we stopped assuming you even *have* a Cur nor an Abs and go back to the basics. You need a "Current" value for these attributes. But I'm going to call it Abs, but it's the current sum, the "absolute value" of the sums. But you do have the meaning of '1' of Abs, let's say, 1 def is 1% of def, 1 Health is, well, 1 health point. (Just remarked that you say one health point, meaning it's an arbitrary unit that doesn't donvert to anything else). But what does that mean, 1% def ? Actually 45% def means that you get missed by 95% of attacks in mosts cases, it's not exactly a percentage, right ? It's a unit. What's one point of held protection ? well, it nullifies itself with one point of held magnitude ! What's a point of Perception ? A feet ! 1% of def is what nullifies 1% of To-Hit...

So, what is Cur ? The only thing I find making sense is an old post from Arcanaville about Cur being something like (Abs-Min)/(Max-Min), meaning that with an attribute being in between 0 and a max, it's the normalized value of Abs to the Max.

Quote:
Yes and no. The way the server works, the engine does an unresistable pass and computes intermediate results for resistance. Then it does a resistible pass and computes all other values given the intermediate resistance. In other words, lets say you have a target with 80% resistance (to something) and it gets hit with a -30% unresistable resistance debuff and a -20% resistable resistance debuff. The game engine calculates the target's intermediate resistance based on all unresistable effects, and gets 80-30=50%. Then it calculates the effects of all resistable effects given that resistance: the -20% debuff is reduced to -10% because of the effective resistance at that moment, and the final resistance drops to 50-10 = 40%.
Ok, I understand, but do you do realize this is inefficient ? You could store the unresistable values somewhere specifically for that, but that would nullify my "resistible cancellation is an irresistible mod of opposite of resited value", the workaround I found was cloning irresistible resistance buffs in another aspect. Also, unresistable resistance debuffs don't exist in the game, as far as I know about player powers. Not even [Rest]. Do you know one that I don't know ? Codewalker, could you do a quick check on the whole powers.bin ? (recreate a City of Data somewhere with a modified algorithm to print the name of the power that bears such an effect)

Quote:
However, one clock later, the server starts over.
Highly unefficient, that's a logic-based test for each irresistible buff on a list for each entity that has irresistible buffs, for each iteration.

Quote:
I did say that, but being able to calculate "moment by moment" is exactly what it sounds like. You don't need to implement a clock, but you should be able to state what the current attribute values are for a *given* moment. If I say "+1.2 seconds" the calculator should be able to say. But it can't, because its not just unclocked, its completely time-unaware. And a completely time-unaware scale summer is something I could do in a single afternoon: that's an extremely tiny component of the whole. Its so small I would never write it time-unaware, because of the strong possibility my code would not be extensible to a clocked environment.
the only thing that needs to be time-aware is the thing that sees the powers and effects and keep tracks of the entities. I would never do an engine without *events*, that is, "entity X wants to launch power Y with target Z" from AI and client, and "auto-power launched" from the *clock*, so at least that is tricky. But I did it as time-aware as it needed to be. Attribmods are not, in essence, time-aware, Effects are. You're lucky I even coded an Effect or Entity class, but that was to have clean and useable code in the long run.

Quote:
I don't see how you are rationalizing it as part of the "powers" engine. The only thing that makes any sort of sense is you're thinking of making the attribmod equivalent of micro-ops and breaking down time-dependent attribmods into micro-attribmods and clocking them outside of the micro-attribmod engine. Which is fine, except that doesn't allow you to redefine the scope of the problem to be writing the micro engine, because that eliminates the bulk of the complexity of the problem.
You've totally seen through me now. But I've not called it complete yet either, the "bulk" of the problem indeed lies here but is similar to making a full power engine, which is going to be done next week-end normally. You do the infrastructure before really coding, you do the data structures before making algorithms and functions that are going to handle them. That is the same here, I made the Entity-Attribute-Aspect, and the (Power)-Effect-Executable hierarchies, what's going to be linking them all is a fully time-Entities-Power-aware engine, which is actually more than just a simple attrib-mod calculator that can calculate modifications at any moment. But it does require that.

Quote:
No one says its impossible. What is true is all non-experts think they are far better than they actually are. In fact, most of the experts tend to think they are better than they actually are also.
In fact, everybody always tend to think they are better than they are, because they don't expect external events that nearly always make you slower, not faster.

Quote:
That's a fair point. I'm working the next two weekends, so I'm going to try to steal some nights and write an attribmod calculation engine. My guess is that given the context we're talking about, that's about 40-50 hours of work for all except the expression engine, entity spawning, attribmod distance effects (basically, inner and outer radius), and boost templates (basically all attribmods will be assumed to be flagged to be powers not enhancements). Maybe some other little flags I'm not considering, like the set bonus ones.

Lets see how long it actually takes.
That was roughly what I was aiming to do. Try, if not keeping tabs of hours, maybe half-days equivalents or something, to measure this 40-50 hours. In which language are you coding it in the end ? Consider using C++ but only its best parts, as I did (no virtual inheritance or new operator overloading, but the namespaces, minute amount of operator overloading, and member methods do come in handy). Also, I think you won't need that, but best of luck anyway.

Enhancement are a different beast, I have an idea of how to implement them, but it's going to be Carte Blanche since I didn't see anything about how they could be handled by the server. But given how the Dual Pistols powers work, and how efficient it's going to need to be, I have this idea. But it'll come later.

I think entity spawning can be done by the movement engine, I mean, very basic entity spawning, like an empty shell, to pass to the power engine for such things as summoning pseudo- and full pets and so on. You could these empty shell for effects that would then only need to provide templates to these empty entity, transforming them into full-fledged Ice Storm and whatnot. Also, you could copy your attributes to them to buff their powers exactly as yours, or as default the movement engine creates clones of you as fork/exec does in UNIX.



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
Let's suppose you are right, you in fact do have Cur that sums the duration-based effects and Abs the others. You anyway need to have a timer on hand for each effect in order to know when to cancel them, and what amount to cancel each effect individually, or you need to reconstruct from adding all the remaining effects, which is the same amount of data but plain computationally inefficient. Something that takes as much or less space and calculation is to keep the list of "timer & cancellation value" per applying effect instance, and you don't need store each sum separately, because "Abs+(Cur-Cancellation)" is "Abs+Cur-Cancellation". So it's more effective to store the total in either Cur or Abs as the result, and apply cancellations over it.
No good. If you have an effect on the target that is resistable, and then the *resistance* expires, you have to recalculate all of the resistable effects. In the general case, you have to recalculate the attribmods for every tick of time in which its theoretically possible for resistance to expire, and dealing with this with special cases just makes things more complex. It makes more sense to recalculate attribmods on every tick of the clock. Otherwise, you're just asking for problems. And I haven't really fully thought about whether there are other failure modes besides expiring resistance, because it would never occur to me to take this short cut in the first place, because its already known to be broken.

Quote:
Also, I didn't find any duration-infinite status effect, Regen, Recovery or Recharge buff or debuff. Only damage, health and endurance modification are "infinite" and "absolute" modification (or am I missing something ?). And those don't have duration-finite modification to their Value (Spectral Wound's damage gets couteracted by a heal, not negative damage). In fact, I didn't find any attribute that needs both of them.
Endurance has both Abs and Cur applied to it. And in fact, Cur modifications on Endurance are permanent. Which actually creates an unanswered question for me: are endurance cur effects flagged to be permanent, or does the game engine presume Cur effects on Endurance are permanent automatically? Both are theoretically possible at the moment, although I suspect its the latter that is true due to a bug that occurred several issues ago that demonstrated what the game engine does when you apply a Cur to health with a duration inadvertently. I would personally code it that way without direct evidence to the contrary.


Quote:
We may be mixing "percentage" with "percents" here, see how this fits: we stopped assuming you even *have* a Cur nor an Abs and go back to the basics. You need a "Current" value for these attributes. But I'm going to call it Abs, but it's the current sum, the "absolute value" of the sums. But you do have the meaning of '1' of Abs, let's say, 1 def is 1% of def, 1 Health is, well, 1 health point. (Just remarked that you say one health point, meaning it's an arbitrary unit that doesn't donvert to anything else). But what does that mean, 1% def ? Actually 45% def means that you get missed by 95% of attacks in mosts cases, it's not exactly a percentage, right ? It's a unit. What's one point of held protection ? well, it nullifies itself with one point of held magnitude ! What's a point of Perception ? A feet ! 1% of def is what nullifies 1% of To-Hit...
The game engine doesn't deal in percentages at all. 1 def would be 1.0 def, which would in effect be 100% defense, but the game engine calls that 1.0. For reference, Focused Fighting offers a base 0.13875 buff to Melee_Attack Cur. To be more precise, it offers 1.85 Scale buff to Melee_Attack Cur, using the Melee_Buff_Def table. For Scrappers, that table contains 0.075 for all levels. So Focused Fighting offers a net 1.85 * 0.075 = 0.13875 buff to Melee_Attack Cur, which we players call "13.875%"


Quote:
So, what is Cur ? The only thing I find making sense is an old post from Arcanaville about Cur being something like (Abs-Min)/(Max-Min), meaning that with an attribute being in between 0 and a max, it's the normalized value of Abs to the Max.
A Cur buff is Scale * Max in value.


Quote:
Ok, I understand, but do you do realize this is inefficient ?
I don't think it is, for the game engine to work in the general case. I believe the special case logic required to do anything else would not make the alternative significantly faster without breaking things.


Quote:
the only thing that needs to be time-aware is the thing that sees the powers and effects and keep tracks of the entities. I would never do an engine without *events*, that is, "entity X wants to launch power Y with target Z" from AI and client, and "auto-power launched" from the *clock*, so at least that is tricky. But I did it as time-aware as it needed to be. Attribmods are not, in essence, time-aware, Effects are.
Attribmods are time dependent effects, and there is no such thing as an effect separate from attribmods in the City of Heroes game. Attribmods are effects: Attrib-mod: Attribute-Modifier. They are the only mechanism for producing an effect in the game.


Quote:
You've totally seen through me now. But I've not called it complete yet either, the "bulk" of the problem indeed lies here but is similar to making a full power engine, which is going to be done next week-end normally. You do the infrastructure before really coding, you do the data structures before making algorithms and functions that are going to handle them. That is the same here, I made the Entity-Attribute-Aspect, and the (Power)-Effect-Executable hierarchies, what's going to be linking them all is a fully time-Entities-Power-aware engine, which is actually more than just a simple attrib-mod calculator that can calculate modifications at any moment. But it does require that.
I'm aware of all that, but my comment stands. Based on what I've seen, there's no way to extrapolate this effort into a full combat engine in four weekends of work; there's no way to extrapolate this effort into even just a full attribmod calculator in four weekends of work: I'm dubious its even possible to extrapolate this into a stripped down version of an attribmod calculator that excludes extensions such as expression evaluation and entity spawning in four weekends. I still believe you're vastly underestimating the scope of the problem, and your code is doing much to narrow down the margin for error that exists for how fast you could possibly do it.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Arcanaville View Post
A Cur buff is Scale * Max in value.
Wait, how can that possibly work for defense?

Max for the attack type attribs increase as you level, that much is evident from the class tables. That hard cap seems to apply even though all the buffs are Cur. Or do you think the code that handles defense just reads Cur and clamps it to Max explicitly, ignoring the normal logic?


 

Posted

Quote:
Originally Posted by Codewalker View Post
Wait, how can that possibly work for defense?

Max for the attack type attribs increase as you level, that much is evident from the class tables. That hard cap seems to apply even though all the buffs are Cur. Or do you think the code that handles defense just reads Cur and clamps it to Max explicitly, ignoring the normal logic?
That's a good question. It seems unavoidable that this requires special handling. Actually, now that I think about it specifically, I wouldn't be surprised if Cur *normally* worked on the range of 0.0 to 1.0 and it was specifically the attributes tied to HitPoints and Endurance that had special handlers. It would explain some of the attribute structure in the attribute tables.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Well, honestly, I suspect even the devs themselves have trouble with that part of it, considering that one of the accepted aliases in the parsing engine for Abs is kCurAbs (kCurrentAbsolute)... ;-)


 

Posted

Quote:
Originally Posted by Arcanaville View Post
That's a good question. It seems unavoidable that this requires special handling. Actually, now that I think about it specifically, I wouldn't be surprised if Cur *normally* worked on the range of 0.0 to 1.0 and it was specifically the attributes tied to HitPoints and Endurance that had special handlers. It would explain some of the attribute structure in the attribute tables.
Quote:
Originally Posted by Codewalker View Post
Well, honestly, I suspect even the devs themselves have trouble with that part of it, considering that one of the accepted aliases in the parsing engine for Abs is kCurAbs (kCurrentAbsolute)... ;-)

Natures way of telling you it's time to rethink.


 

Posted

Quote:
Originally Posted by Codewalker View Post
Well, honestly, I suspect even the devs themselves have trouble with that part of it, considering that one of the accepted aliases in the parsing engine for Abs is kCurAbs (kCurrentAbsolute)... ;-)
Well, I had a hint there were Cur/Abs issues going all the way back to beta when I realized melee had 10,000% resistance to knock.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Arcanaville View Post
I don't think it is, for the game engine to work in the general case. I believe the special case logic required to do anything else would not make the alternative significantly faster without breaking things.
There's a strong parallel here with 3D geometry calculations in the rendering part of a game loop. On each game tick, the naive implementation calculates all the absolute positions of objects' rasterizations based on the matrix transforms for not just the objects themselves but all intermediate objects in the scene-graph that can have them. For example, if a car object is actually composed of wheels that can turn and a frame that hosts those wheels, then rasterizing the wheels involves knowing the current transform for the car, as well as the transform of the wheels themselves (think of the results of an explosion that hurl a moving car past the viewer).

There are common tricks that can be applied to save the matrix math involved in recomputing the leaf-node object transformations, if you believe that there are parts of the scene graph that remain unchanged between game ticks. Such tricks could be played here too: you could consider the attribmod formulas to be a graph that must be traversed on each tick, dirty the nodes that change between ticks, and use cached values for everything else. In the (probably extremely unlikely) event that nothing at all changed between ticks, this would allow the whole computation to be skipped.

However, I would avoid trying to get that complicated on the first pass. If the attribmod abstraction is written correctly, this kind of optimization can be applied later without too much pain. And you'd want to actually profile the full system before deciding to design this: there may be parts of the full engine that swamp what you're doing here, or you may find in real world cases that not enough can be cached between ticks to justify the increased complexity. (There's some quote about premature optimization being the root of all evil...)

BTW, I talked to a few other folks today at work about this, and the reaction was pretty universally "That's completely insane and I hope they do it".


And for a while things were cold,
They were scared down in their holes
The forest that once was green
Was colored black by those killing machines

 

Posted

Quote:
Originally Posted by Arcanaville View Post
Which actually creates an unanswered question for me: are endurance cur effects flagged to be permanent, or does the game engine presume Cur effects on Endurance are permanent automatically? Both are theoretically possible at the moment, although I suspect its the latter that is true due to a bug that occurred several issues ago that demonstrated what the game engine does when you apply a Cur to health with a duration inadvertently. I would personally code it that way without direct evidence to the contrary.
Now that I think about it, that probably depends on the ApplicationType of the attribmod. If it's OnTick, it'll try to reapply every tick, but if it's OnActivate then it will only apply when the power is first activated.


 

Posted

Quote:
Originally Posted by Arcanaville View Post
No good. If you have an effect on the target that is resistable, and then the *resistance* expires, you have to recalculate all of the resistable effects. In the general case, you have to recalculate the attribmods for every tick of time in which its theoretically possible for resistance to expire, and dealing with this with special cases just makes things more complex. It makes more sense to recalculate attribmods on every tick of the clock. Otherwise, you're just asking for problems. And I haven't really fully thought about whether there are other failure modes besides expiring resistance, because it would never occur to me to take this short cut in the first place, because its already known to be broken.
Just to get a pictured case, and a test case in AE, what do we want to happen when this happens ?:
Brute has 40% res to energy, brute gets hit by thermal radiation.melt armor, brute toggles off its defensive toggle, melt armor expires.

We want to brute to get back to 0% res. But what happens during the time the melt armor is the only remaining effect ? is it the full debuff or the resisted debuff ?

Quote:
Endurance has both Abs and Cur applied to it. And in fact, Cur modifications on Endurance are permanent. Which actually creates an unanswered question for me: are endurance cur effects flagged to be permanent, or does the game engine presume Cur effects on Endurance are permanent automatically? Both are theoretically possible at the moment, although I suspect its the latter that is true due to a bug that occurred several issues ago that demonstrated what the game engine does when you apply a Cur to health with a duration inadvertently. I would personally code it that way without direct evidence to the contrary.
Or isn't it strange enough to still think Cur mods as being temporary ? We at least need a simple way to make +5% mods, because of regen and recovery.

Quote:
The game engine doesn't deal in percentages at all. 1 def would be 1.0 def, which would in effect be 100% defense, but the game engine calls that 1.0. For reference, Focused Fighting offers a base 0.13875 buff to Melee_Attack Cur. To be more precise, it offers 1.85 Scale buff to Melee_Attack Cur, using the Melee_Buff_Def table. For Scrappers, that table contains 0.075 for all levels. So Focused Fighting offers a net 1.85 * 0.075 = 0.13875 buff to Melee_Attack Cur, which we players call "13.875%"
Of course, I was using brute innocence. It does make sense to have 1.0 def = 100% because you use percents afterwards in the to-hit formula. But the game does deal with percentage, with regen and recovery at least, it did and still does with the old Moment of Glory (I think). Resistance is also percentage based, but def is not. Yet, the game real numbers and city of data still display resistance and def in percents whereas they do not tend to be equivalent at all. 50% resistance does mean 50%. 50% def means nothing if you don't have the emitter's to-hit.

Quote:
A Cur buff is Scale * Max in value.
Codewalker and I seem to differ from this conception. Just a question: where did you get the knowledge that defense buffs are Cur modification ? (OTHER than it's duration-based) I want the exact, string from the game, quote. I expect you're going to give me a funny polish notation expression again, but go.

Quote:
I don't think it is, for the game engine to work in the general case. I believe the special case logic required to do anything else would not make the alternative significantly faster without breaking things.
You could at least trigger recalculation only when you get an irresistible resistance mod applied. As I said, they tend to be rare (except when raids buffers are spamming >_>)

Quote:
Attribmods are time dependent effects, and there is no such thing as an effect separate from attribmods in the City of Heroes game. Attribmods are effects: Attrib-mod: Attribute-Modifier. They are the only mechanism for producing an effect in the game.
ooooh but there are different effects in powers than attribmod my dear. There are Summons, there are GrantPowers, RevokePowers, SetModes & UnSetModes, SetEffectChance, and I could be missing some others.

Quote:
I'm aware of all that, but my comment stands. Based on what I've seen, there's no way to extrapolate this effort into a full combat engine in four weekends of work; there's no way to extrapolate this effort into even just a full attribmod calculator in four weekends of work: I'm dubious its even possible to extrapolate this into a stripped down version of an attribmod calculator that excludes extensions such as expression evaluation and entity spawning in four weekends. I still believe you're vastly underestimating the scope of the problem, and your code is doing much to narrow down the margin for error that exists for how fast you could possibly do it.
As you said it yourself, "we'll see".

Quote:
Originally Posted by Arcanaville View Post
Well, I had a hint there were Cur/Abs issues going all the way back to beta when I realized melee had 10,000% resistance to knock.
I don't see the point here. Status resistance decreases duration, not magnitude (another special case ? Yes, I have to code that)



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
Just to get a pictured case, and a test case in AE, what do we want to happen when this happens ?:
Brute has 40% res to energy, brute gets hit by thermal radiation.melt armor, brute toggles off its defensive toggle, melt armor expires.

We want to brute to get back to 0% res. But what happens during the time the melt armor is the only remaining effect ? is it the full debuff or the resisted debuff ?
Answer is, we want to have the unresisted effect. So my implementation is (going to) be incorrect. Well was, because I know that I need to correct this.
Against melt armor mobs in AE, my resistance went 33.38,18.99 then -21.6 then 0. So they *do* recalculate everything everytime res or unresisted res gets modified, so you've got to store the applied value and delay the cancellation value computation until, well, the cancellation.



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !

 

Posted

Quote:
Originally Posted by Codewalker View Post
Now that I think about it, that probably depends on the ApplicationType of the attribmod. If it's OnTick, it'll try to reapply every tick, but if it's OnActivate then it will only apply when the power is first activated.
Except that feature is relatively new, so that had to be arbitrated some other way in the past.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Mister_Bison View Post
I don't see the point here. Status resistance decreases duration, not magnitude (another special case ? Yes, I have to code that)
That's technically not true. Technically speaking, Magnitude Resistance decreases magnitude using the Scale * (1 - Res) formula. Duration Resistance decreases duration using the Scale / (1 + Res) formula.

Which one you use is based on the type of the attribmod. This is another important feature of the game engine. Strength and Resistance all affect the net scale value of the effect. But whether that net scale value is the magnitude or the duration of the effect depends on a type flag. Virtually all mez powers have their mez effects typed "Duration" and that's why slotting enhancements into them increases their duration. Damage effects are typed "Magnitude" and thus enhancements boost the magnitude of those effects, not duration. Its not baked into the attribute type nor the enhancements how this works: its keyed off a type field.

Interestingly, mez protection buffs are often typed magnitude, not duration. That means in theory if you could slot them with mez enhancement, your protection would get higher. You can't do that, so you can't see this effect. But you *can* see this effect if you have someone Benumb you in PvP: that will cause your mez protection magnitude to actually go down, because those debuffs affect mez strength, and that strength reduction in turn makes your mez protection pulses drop in magnitude, because they are typed magnitude.

In any case, this is just an informative tangent. The obvious reason why 10,000% equals confused dev is because someone put "100" into the powers spreadsheet for that resistance, thinking "100% resistance" when the correct thing to do was to put in "1.0" which is 100% resistance. This error was never corrected, because there's no obvious sign of a problem when you make this error: both make you absolutely immune to all (except unresistable) knockback. Because knockback effects are generally typed "Magnitude."

Moreover, at the beginning of time the res cap was 1.0 all around, so even though duration resistance could logically use higher values, higher values were not possible. cf: Hamidon.

The rule is: Strength and Resistance can only affect Magnitude or Duration, not both, and both always affect the same thing. So if slotting enhancements into KB powers increases the mag of the KB, KB resistance reduces the mag of those same powers. They go together because of a fundamental property of the way the game engine handles scale values of powers.

Coincidentally I was just starting to write some code for my attribmod engine and was thinking about that specific issue. Because for efficiency sake, it makes no sense to push around all the data for the attribmods; in a practical sense attribmods are static and all you need is to use pointers to them. That's almost certainly what the actual game engine does. But you do need to pass one piece of information around: the effective scale value of the attribmod when its instantiated. And that's because it will be modified by the entity's tables (usually) and the entity's strength. But you can precompute that because an attribmod's net scale value is immutable upon creation. It can be affected by variable target resistance, but not by variable caster strength.

Thus, you end up with something like this:

Code:
    def applyAttribmod(attribmodId, powerId, entityId, triggerTime, trueScale):
        expireTime = triggerTime + AttribmodDB[attribmodId][kduration]
        nextAct = triggerTime
        attribmodStack.append([attribmodId, powerId, entityId, triggerTime, trueScale, expireTime, nextAct])
I believe that is the minimum amount of data you need to dynamically track for an attribmod: the rest is power database lookup. Technically, powerId is redundant, but I have a feeling for efficiency purposes I'm going to want to keep that around for the stacking code. Trigger time is a repurpose: without a powers engine surrounding the attribmod engine, there's no way to tell the engine to do a sequence of events. So I need that to allow for injecting a set of attribmods to simulate a sequence of powers. But that's not wasted code because trigger is just going to transmogrify into attribmodDelay tracking in the general case.

After 1.5 hours of coding, I have a data import routine for archetype tables, some class stuff for entities, and the definitions for basic attribmods. In terms of actual code that does something, here's what I got:

Code:
while True:
    # this increments the clock by 1/30th of a second with alignment
    if clock % 100 == 0:
        clock = clock + 34
    else:
        clock = clock + 33



    if clock > endtime:
        break
No, I'm not kidding. I believe if you don't start with thinking about clocking, you're screwed. Thinking about how I was going to track time led me to think about activation periods and attribmod expiration, and that led me to think about managing attribmod lists, and that led me to think about the minimum amount of data necessary to track an attribmod in a pseudo-queue, and that led me to think about entity structures, and that led me to decide to write an archetype data importer, and that brought me back to attribmod queues, and that led me to think about Scale computations, and that will lead me to getting ready for bed.

71 actual lines of code, ~90 minutes. Going to try to tackle Abs, Str, and Res tomorrow. I have an idea on how to manage Cur without having to track a lot of funky exceptions, but that will require more algorithmic thought.


[Guide to Defense] [Scrapper Secondaries Comparison] [Archetype Popularity Analysis]

In one little corner of the universe, there's nothing more irritating than a misfile...
(Please support the best webcomic about a cosmic universal realignment by impaired angelic interference resulting in identity crisis angst. Or I release the pigmy water thieves.)

 

Posted

Quote:
Originally Posted by Arcanaville View Post
Code:
while True:
    # this increments the clock by 1/30th of a second with alignment
    if clock % 100 == 0:
        clock = clock + 34
    else:
        clock = clock + 33



    if clock > endtime:
        break
Why do you care about alignment? Won't this cause some weird aliasing effects? It seems much simpler (and IME more expected) to have each tick be the same length.

Edit: Maybe this is what people mean when they say "Arcanatime". Still seems strange though.

Also, further thought, maybe this is because powers durations are in seconds instead of ticks, in which case not adding the extra millisecond will cause aliasing. You could fix that with rounding... probably... but then that probably just gives you this result anyway...

Interesting stuff.


And for a while things were cold,
They were scared down in their holes
The forest that once was green
Was colored black by those killing machines

 

Posted

Quote:
Originally Posted by Arcanaville View Post
That's technically not true. Technically speaking, Magnitude Resistance decreases magnitude using the Scale * (1 - Res) formula. Duration Resistance decreases duration using the Scale / (1 + Res) formula.

Which one you use is based on the type of the attribmod. This is another important feature of the game engine. Strength and Resistance all affect the net scale value of the effect. But whether that net scale value is the magnitude or the duration of the effect depends on a type flag. Virtually all mez powers have their mez effects typed "Duration" and that's why slotting enhancements into them increases their duration. Damage effects are typed "Magnitude" and thus enhancements boost the magnitude of those effects, not duration. Its not baked into the attribute type nor the enhancements how this works: its keyed off a type field.

Interestingly, mez protection buffs are often typed magnitude, not duration. That means in theory if you could slot them with mez enhancement, your protection would get higher. You can't do that, so you can't see this effect. But you *can* see this effect if you have someone Benumb you in PvP: that will cause your mez protection magnitude to actually go down, because those debuffs affect mez strength, and that strength reduction in turn makes your mez protection pulses drop in magnitude, because they are typed magnitude.
Neat, so there is still only one resistance and one strengh for an entity attribute and it does become "Magnitude resistance/strengh" or "duration resistance/strengh" because the effect is flagged to be magnitude-resisted or the other, and this flag is a boolean. Also, one same attribute can be duration or magnitude at the same type in different powers, so no hard coding that in the "modification" of the value when the effect is resistible. Actually, that makes it a 3-value flag whether the effect is to be duration-resisted, magnitude resisted, or not at all. Makes me wonder if there isn't a fourth possibility.

About buffs to status and status protection, get a character with power boost and Tactics or any Leadership power that protects against status. I'd do it if I wasn't at work.

Quote:
In any case, this is just an informative tangent. The obvious reason why 10,000% equals confused dev is because someone put "100" into the powers spreadsheet for that resistance, thinking "100% resistance" when the correct thing to do was to put in "1.0" which is 100% resistance. This error was never corrected, because there's no obvious sign of a problem when you make this error: both make you absolutely immune to all (except unresistable) knockback. Because knockback effects are generally typed "Magnitude."

The rule is: Strength and Resistance can only affect Magnitude or Duration, not both, and both always affect the same thing. So if slotting enhancements into KB powers increases the mag of the KB, KB resistance reduces the mag of those same powers. They go together because of a fundamental property of the way the game engine handles scale values of powers.
Yes, knockback, knockup and repel have reduced magnitude when resisted., since duration in these would be... strange oO

Quote:
Coincidentally I was just starting to write some code for my attribmod engine and was thinking about that specific issue. Because for efficiency sake, it makes no sense to push around all the data for the attribmods; in a practical sense attribmods are static and all you need is to use pointers to them. That's almost certainly what the actual game engine does. But you do need to pass one piece of information around: the effective scale value of the attribmod when its instantiated. And that's because it will be modified by the entity's tables (usually) and the entity's strength. But you can precompute that because an attribmod's net scale value is immutable upon creation. It can be affected by variable target resistance, but not by variable caster strength.
Truths here. You only need powers in one place and only ID them from the entity. Like in databases. You could also have one place for effects and ID them from powers, but I don't know if this would be efficient (indirection is indirection). The "scale" value is an inherent part of the attribmod and should be left there if you plan on keeping the value in databases, but if indeed you store these values in the entity, you can already do the Scale*table[level]. All that's remaining to do when applying is get the caster buffs and enhancement or ignore them, and apply the resistance or ignore it. But strengh *does* vary between attribmods calculation. What happens if you code Buildup and a damage power and execute them in sequence ? Will the damage be buffed properly if you account for the strengh only when linking powers to entities ? Will you make a pass on all the entities powers and effects to buff their strengh, even though it's going to be used for a handful power launches ?

Quote:
Thus, you end up with something like this:

Code:
def applyAttribmod(attribmodId, powerId, entityId, triggerTime, trueScale):
        expireTime = triggerTime + AttribmodDB[attribmodId][kduration]
        nextAct = triggerTime
        attribmodStack.append([attribmodId, powerId, entityId, triggerTime, trueScale, expireTime, nextAct])
I believe that is the minimum amount of data you need to dynamically track for an attribmod: the rest is power database lookup. Technically, powerId is redundant, but I have a feeling for efficiency purposes I'm going to want to keep that around for the stacking code. Trigger time is a repurpose: without a powers engine surrounding the attribmod engine, there's no way to tell the engine to do a sequence of events. So I need that to allow for injecting a set of attribmods to simulate a sequence of powers. But that's not wasted code because trigger is just going to transmogrify into attribmodDelay tracking in the general case.
Are you going to code a script ? Or are all your powers going to be resolved at t=0 ? That's going to be wasted code though. You could already put that as delay already and decrease the counter every instant.

In my idea of implementation, you should keep time like that until this power is the next one to resolve on this entity, when it's really needed to keep track of the "delay remaining".

Quote:
After 1.5 hours of coding, I have a data import routine for archetype tables, some class stuff for entities, and the definitions for basic attribmods. In terms of actual code that does something, here's what I got:

Code:
while True:
    # this increments the clock by 1/30th of a second with alignment
    if clock % 100 == 0:
        clock = clock + 34
    else:
        clock = clock + 33
    if clock > endtime:
        break
No, I'm not kidding. I believe if you don't start with thinking about clocking, you're screwed. Thinking about how I was going to track time led me to think about activation periods and attribmod expiration, and that led me to think about managing attribmod lists, and that led me to think about the minimum amount of data necessary to track an attribmod in a pseudo-queue, and that led me to think about entity structures, and that led me to decide to write an archetype data importer, and that brought me back to attribmod queues, and that led me to think about Scale computations, and that will lead me to getting ready for bed.
I think you're overdoing it, if arcanatime is exactly 132ms and not 133,33..., then the clock you're looking for is 33ms, not 33,33333... ms. This kind of exact calculation is going to take its toll on the server.

Also, I already thought of all that, it is sorted out, I just wanted to have sorted out the formulas before I went forward. If it's just a matter of adding variables to structures, it's not a problem. If you have to code new functions for new cases, it's another matter.

Quote:
71 actual lines of code, ~90 minutes. Going to try to tackle Abs, Str, and Res tomorrow. I have an idea on how to manage Cur without having to track a lot of funky exceptions, but that will require more algorithmic thought.
Then again you should not go into that part like me until things about Cur/Abs are sorted out.

Also, you didn't answer my question about whether you did have evidence Cur is used for time-limited attribmods, or Cur is the time-limited attribmods-dedicated storage value because it is. Is that going to be answered any day or are you keeping your sources a secret ? I'm a scepticist, so I need evidence. At least answer what line (in powers.bin ?) did say defense buffs were Cur mods, without modifying the wording (as Codewalker said "kCurAbs", and I saw kMeter...

oh shucks.

isn't kCurAbs a sort of pointer/flag to designate which of Abs or Cur is gonna be moded ? like kMeter could be a pointer to a meter/attribute, and these variables/aliases are part of the attribmod attributes ??

Please, Codewalker, could I have a look at Mids and City of Data interpreters of powers.bin ? This could answer so much.



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !

 

Posted

With the way that NCsoft has treated us, with what I have learned about other games such as Aion losing money. Their need to give huge severance pay to employee's that they were laying off. NCsoft putting more resources to unproven projects such as Blade and Soul here in the States and using resources to develop Wildstar. But they do not want to go with a game that was making some money for them. I now serious question their business sense.

If they are throwing away this game and it is making good money for them. Then I would say that they are dumb because they could've canned Aion and that would've helped them out a lot. So since I have my doubts about their business since I will not touch another NCsoft product ever again. Now if they change their mind and show me that they have some good business sense. Then I would gladly start playing some of their games again.

Just think I was seriously considering trying GW2 sometime in the future. But now I will not touch it. What is next will they get rid of a proven money maker like Lineage 2, when that game according to a news article. Sorry do not remember what article it was. But it said that it is one of the biggest money makers.

So I say farewell to all until we meet in another non NCsoft title.


Ebony Fists: Level 50 DM/Regen Scrapper, Gloom Piston Robotics/Dark mastermind level 34, QueenFireMare: Level 34 Fire blaster (pure fire),

 

Posted

Quote:
Originally Posted by Arcanaville View Post
Except that feature is relatively new, so that had to be arbitrated some other way in the past.
I think it's been around at least since CoV. At a glance some very old powers use OnActivate (5th column inherent resistances), so whenever it was added, the defaults must have been populated from whatever used to determine that behavior.

Quote:
Originally Posted by Mister_Bison View Post
Actually, that makes it a 3-value flag whether the effect is to be duration-resisted, magnitude resisted, or not at all. Makes me wonder if there isn't a fourth possibility.
Technically the engine has separate flags for whether resistance (and combat mods) affect magnitude or duration.

Practically, and this is something I went back and forth with Arcana on a while back, it seems that these flags are automatically assigned by whatever tools the devs used to compile the data. So effectively it is based on the type of the effect. IIRC, based on datamining, I determined that there is a fourth option -- if a Constant type effect is resistible, both its magnitude and duration will be resisted.

Constant attribmods are ones where the Scale is not used at all; instead the base Magnitude and Duration from the power definition is used. They're fairly rare, however, and almost always use one of the 'special' Attribs that isn't really an attrib at all, like GrantPower.

Quote:
At least answer what line (in powers.bin ?) did say defense buffs were Cur mods, without modifying the wording (as Codewalker said "kCurAbs", and I saw kMeter...
It's the Type field of the attribmod. I don't know of any way to directly determine that in-game, though real numbers gives you some clues based on how it formats the numbers.

CurAbs is just an alias for Abs. I have no idea how often it's used, as we only have the binary representation of the data, not the source text files that it's compiled from.

Many of the constants in the game engine are prefixed with 'k'. That doesn't really mean anything, it's just a convention that they used for some of the constants. Probably because all of them go into a giant global hash table, and it's to try to prevent the inevitable namespace collisions.

Here's the binary representations that are defined for attribmod type:
kCurrent=0x00000000
kMaximum=0x00000004
kStrength=0x00000008
kResistance=0x0000000C
kAbsolute=0x00000010
kCurrentAbsolute=0x00000010
kCur=0x00000000
kMax=0x00000004
kStr=0x00000008
kRes=0x0000000C
kAbs=0x00000010
kCurAbs=0x00000010

You'll notice these are separated by 4. The normal attribs themselves are as well. For attribs, the ID number also doubles as an index into the memory block where the attributes are stored (32-bit single precision floats). My theory is that on the server side, it keeps a separate copy of that block for each aspect, so the server keeps 2300 bytes worth of data on hand to describe the combat state of every entity. That's 115 attributes * 4 bytes = 460 bytes * 5 aspects = 2300.

Quote:
like kMeter could be a pointer to a meter/attribute, and these variables/aliases are part of the attribmod attributes ??
Meter (aka kMeter) is an attrib just like HitPoints or Endurance. The client uses it to draw the 'tertiary bar' for things like Fury or Domination. It's one of the few attribs that is kept in sync between the client and the server, because it's used for the UI.

'Rage' is the attrib that is actually granted by things like Brute and Dominator attacks. Brutes have an inherent power that on every tick gives them Meter based on how much Rage they have. IIRC, the damage buff is based on the current value of Meter, forming a kind of feedback loop (which the inherent power that handles Fury decay takes advantage of).


 

Posted

Quote:
Originally Posted by Codewalker View Post
Technically the engine has separate flags for whether resistance (and combat mods) affect magnitude or duration.
Yeah I understood that. But what's the point of knowing this powers's duration or magnitude is resisted, when it's irresistible ? =) But you need another bit anyway. I want ternary computer =)

Quote:
Practically, and this is something I went back and forth with Arcana on a while back, it seems that these flags are automatically assigned by whatever tools the devs used to compile the data. So effectively it is based on the type of the effect.
So is there any need to have that flag then ? Can't we use the same determining factor ?

Quote:
IIRC, based on datamining, I determined that there is a fourth option -- if a Constant type effect is resistible, both its magnitude and duration will be resisted.

Constant attribmods are ones where the Scale is not used at all; instead the base Magnitude and Duration from the power definition is used. They're fairly rare, however, and almost always use one of the 'special' Attribs that isn't really an attrib at all, like GrantPower.
How do you resist the magnitude and duration of Grant Power !? I mean, what does these even mean ?

Quote:
It's the Type field of the attribmod. I don't know of any way to directly determine that in-game, though real numbers gives you some clues based on how it formats the numbers.
Well, the game certainly isn't going to tell you your buff gives 0.13 defense, it is not pretty (nor big enough ! =) ), it could just be formatting (especially in cases of defense and To-Hit, where things can go above 100%). So I'm not going to take real number formatting for anything, the order yes, but the formatting doesn't mean anything.

Quote:
CurAbs is just an alias for Abs. I have no idea how often it's used, as we only have the binary representation of the data, not the source text files that it's compiled from.

Many of the constants in the game engine are prefixed with 'k'. That doesn't really mean anything, it's just a convention that they used for some of the constants. Probably because all of them go into a giant global hash table, and it's to try to prevent the inevitable namespace collisions.

Here's the binary representations that are defined for attribmod type:
kCurrent=0x00000000
kMaximum=0x00000004
kStrength=0x00000008
kResistance=0x0000000C
kAbsolute=0x00000010
kCurrentAbsolute=0x00000010
kCur=0x00000000
kMax=0x00000004
kStr=0x00000008
kRes=0x0000000C
kAbs=0x00000010
kCurAbs=0x00000010
Could I ask where you did get this string-value map ? Also... I see things missing here. There is a Max to Max (a MaxMax), a Max and MinRes, and a MaxStr too. Those maybe aren't in the attributes, so where are they ? the MaxMax health gets recalculated everytime there is a Max modification ? The MaxStr is too, or is it fixed ? Is Maxresistance an entity-independant constant ?

Quote:
You'll notice these are separated by 4. The normal attribs themselves are as well. For attribs, the ID number also doubles as an index into the memory block where the attributes are stored (32-bit single precision floats). My theory is that on the server side, it keeps a separate copy of that block for each aspect, so the server keeps 2300 bytes worth of data on hand to describe the combat state of every entity. That's 115 attributes * 4 bytes = 460 bytes * 5 aspects = 2300.
Very clever of them. It can be used for anything that is 4bytes wide... including pointers on non x86-64 machines. Gonna do that in my code so that will force it to have it optimized this way. That will throw my caching off though.

Quote:
Meter (aka kMeter) is an attrib just like HitPoints or Endurance. The client uses it to draw the 'tertiary bar' for things like Fury or Domination. It's one of the few attribs that is kept in sync between the client and the server, because it's used for the UI.

'Rage' is the attrib that is actually granted by things like Brute and Dominator attacks. Brutes have an inherent power that on every tick gives them Meter based on how much Rage they have. IIRC, the damage buff is based on the current value of Meter, forming a kind of feedback loop (which the inherent power that handles Fury decay takes advantage of).
I suspected so, would have made this bar as an attribute, but wanted to check that myself, so thanks for the confirmation. Thanks for the insight about the brute's and dom's inherents too.



WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !