Ok... NOW I'm sad.
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. |
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.)
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 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. |
You're going to special case resist modifiers separate from all other modifiers? |
You can't rely on City of Data for order of operation. |
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) |
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. |
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. |
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 !
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)
|
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.
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) |
Be well, people of CoH.
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
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 ?
|
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 ! |
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%.
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. |
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. |
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.
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. |
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.)
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.
|
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)
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. |
All of them are. Movement buffs are sometimes Cur. Defense buffs almost always are.
|
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.
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. |
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. |
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. |
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. |
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. |
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 !
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. |
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. |
Ok, I understand, but do you do realize this is inefficient ? |
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'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. |
[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.)
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?
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? |
[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.)
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)... ;-)
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.
|
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.
[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.)
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 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
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.
|
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.
|
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 ?
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. |
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%" |
A Cur buff is Scale * Max in value. |
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. |
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. |
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. |
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 !
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 ? |
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 !
[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.)
I don't see the point here. Status resistance decreases duration, not magnitude (another special case ? Yes, I have to code that)
|
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:
def applyAttribmod(attribmodId, powerId, entityId, triggerTime, trueScale): expireTime = triggerTime + AttribmodDB[attribmodId][kduration] nextAct = triggerTime attribmodStack.append([attribmodId, powerId, entityId, triggerTime, trueScale, expireTime, nextAct])
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:
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
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.)
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 |
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
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. |
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.
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. |
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]) |
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".
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 |
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.
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. |
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 !
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),
Except that feature is relatively new, so that had to be arbitrated some other way in the past.
|
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.
|
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.
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... |
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.
like kMeter could be a pointer to a meter/attribute, and these variables/aliases are part of the attribmod attributes ?? |
'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).
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. |
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. |
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). |
WE ARE HEROES. THIS IS WHAT WE DO.
City et moi, �a colle !
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.
[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.)