Jump to content

UberGuy

Members
  • Posts

    649
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by UberGuy

  1. The problem there is that I'd have to start parsing expressions to turn into plain-ish English wording, which is a level of challenge I don't think I'm up for (or that probably makes sense to invest in this feature - I realize this is already super gold-plated). I believe to achieve that realistically I'd just end up having to build special case handling, like looking for certain operations (comparing your health to thresholds for example) and hope they weren't buried in something more complex that changed their meaning. At that point I think the right thing to do would just short-circuit most of the process and say: "If this power, say this effect description." An alternative I was noodling for handling things like Preventive Medicine is saying that if we see the same effect (like +Absorb) with both a 100% chance and a non-100% chance, but both with (different) conditions, just report that simply as a single "Chance of X". No, but I do rather like the idea of having a more accurate name as a summary of the effect. Fortunately, most effects aren't so silly as the few examples above. They're definitely outliers.
  2. It comes out as "Attuned Essence Transfer: Recharge/Chance for +Health". Which seems legit, despite the piece's functional oddity. (I remember discussions about this thing coming up before. It really doesn't seem right.) Edit: While I don't think this piece would trigger this logic, I did have to handle an interesting edge case where you have procs that have < 100% chance to give you a power that has its own < 100% chance of triggering. I forget what thing it was, but I found something with a name that included "Chance of Chance of X", heh. That's silly so I now collapse that down to a single "Chance of". Another interesting case along the same lines is the Preventive Medicine "proc". This is a "proc" more in the old-school "procedural" meaning of that contraction than what we usually mean here for CoH. It grants a global power that essentially acts as a health monitor and fires of the +Absorb based on two different conditions. If your health is between 31% and 75 of max it has a 10% chance to give you +20% of your max HP as absorb If your health is below 31% of max it has a 100% chance of the same The name generation for this is a bit weird, but I've left it as-is for now, as it's ... kind of right. "Preventive Medicine: Chance for +Absorb/+Absorb". It works out that way because the naming logic doesn't have any handling for non-random conditional behavior. It sees both a non-100% chance for +Absorb and a 100% chance for +Absorb and lists them both. Which is ... kind of legit - I can't think of any of the existing proc/global names handling conditional logic either. (The dev-granted name for this thing is perhaps less confusing, but it's much more opaque.) Another similar example I've caught is the Kheldian form bonus global. It comes out as "Attuned Kheldian's Grace: Recharge/+Dam(All)/+Max HitPoints/+Res(All)". Now clearly it doesn't do all those things at the same time - what it grants is a function of what form your're in, and again the code doesn't process conditiions. But I'm leaning towards leaving it as-is, because it really is a lot more informative this way. I could give in and just put these pieces in the same bucket I did with the "Chance for Build Up" procs and hard-code their dev-granted names. Or, maybe there's a concise way to say "Conditional X / Conditional Y". I'd prefer a shorter worth than "Conditional" but maybe that'd be OK. It's not like "Chance for" is super short either.
  3. Something I've been working on for some time is a way of generating enhancement information programmatically, based on what an enhancement's power definition actually does, and not just taking its name at face value. The reason is that, like many thing in CoH, enhancements follow conventions, not rules. That is to say there are "rules" the powers devs follow when creating them, but the game has zero code-based enforcement for nearly any of them. The HC powers devs do use tools to create and edit powers (far better tooling it seems than the Cryptic or Paragon devs had), and these tools do offer sane defaults and some guardrails, but they still don't require following the "rules". There are ... a lot of things to take into account here. Because of the conventions we see as players, what we think of as enhancements roll up a lot of fairly complex behavior into a somewhat neat package. For example, Damage enhancements always bundle the eight distinct damage types. Defense enhancements bundle the eleven defenses (8 typed and 3 positional), and so on. Heal enhancements bundle boosts for +maxHP, +HP, +regen and +absorb. When you inspect an enhancement's power data, what you see are a bundle of attribute modifiers, not these enhancement names.* Some groupings are more complicated than others. For example, movement enhancements don't all boost the same set of things. Some include Range (for teleport) and some don't. Some boost jump speed but not jump height, while others boost both. One way to construct an enhancement's name from its attribmods takes a process I call folding, where you recognize a group of attribmods as mapping to a single enhancement "aspect" like Damage, Defense, Heal, etc. You pop out the recognizable groups an build up a name from the aspects. As mentioned above for travel boosts, different groupings of attribmods might map to the same nominal "aspect". You keep mapping groups to aspects until you don't have any recognizable groups left, and then you're left with things that don't usually belong to a group (like, say, Accuracy or Recharge) - their attribmod name is their aspect. Note that this would be impossible general for powers across the board - this really only works because enhancements usually only do certain things. They apply strength aspect buffs to effects in a power. But then we get into procs and "globals". These are much more general powers, and can, within some limits basically do anything. Describing what they do programmatically was really challenging. There's not as much use for "aspect folding" as I describe above, though there are some patterns we see where it's still useful. The process is usually simpler though - powers like these tend to do one thing, and if it's provide a "bulk" benefit like +Dam(All) or +Def(All) that's usually easy to see directly without having to pluck "aspects" out of the bag of things the power does one at a time. But still, procs do a lot of things. They summon entities. Sometimes those entities are "patch powers" that just fire off a power once and then disappear. Other times they grant the caster or the target another power. In both the summoning and granting cases, you have to look up that power and see what it does. And you have to distinguish "patch powers" from actual combat entities like Fiery Orb. "Global' bonuses are a whole other bag - a lot of "global" enhancements do absolutely nothing on their own. For example, the Aegis "F" (sixth) piece provides no actual enhancement benefit. Instead, the Aegis set definition defines a rule which says that having the 6th piece slotted means you automatically get the "Set Bonus.Set Bonus.Aegis: Psionic/Status Resistance" bonus. So to create a display name for that, you need to know this is what happens and know to go look up what that power does, and not just inspect the boost itself. (You'll never see the "global" bonus anywhere if you look only at the raw power definition for the sixth Aegis". You'll see it in CoD's data because I explicitly build that relationship into CoD's data so CoD can tell you about it.) Finally, the naming conventions we see, especially for procs, globals and other special enhancements are pretty free-form. Writing code that would actually match every name we see is basically impossible, even when the names are right. Mostly, what I've written is very close, if not identical to existing naming standards. Sometimes it's more wordy - I try to limit how wordy it gets, but I've chosen to leave some generated names alone because they are actually informative. For example, the generated names make a distinction between "Chance of A, B" and "Chance of A / Chance of B". In the first case, A and B are linked and only happen together. In the second case, A and B can happen independently. There are two special effects whose generated names I "cheat" on. This was because their conventional name is very well understood but a bit hard to back into from first principles. The two powers are the various "Chance for Build Up" procs (which all grant the same power) and the Blaster ATO chance for +mez res/protection. When I see those powers referenced in a computed effect name, I just emit their known name rather than try to derive it. Given how many special boost effects there are, I'm pretty proud of only needing to resort to that in two cases. Once I threw in some additional logic for inspecting and auditing the rules for expected enhancement scales (think about things like the way set pieces divide boost strength between aspects in multi-aspect enhancements) and I've written around 1800 lines of code just dedicated to enhancements. Now, bear in mind, this is Python code with generous comments and whitespace (4-space indentation and 1-2 line spacing between important sections, plus a lot of data declaration devoted to things like what attribmods make up a boost "aspect". Still, it's a lot of code, and something I've been crafting on and off in the background literally for months. I plan to use this to augment the display of powers that are themselves enhancements (boosts), providing a computed name (as a way to audit against the dev-written display name) plus a bunch of other summary information about the enhancement's behavior. Some of this is nominally obvious from the name, but with these added displays it will be easier to confirm that the boost really does what its name says it does. As of this posting I have not yet updated the site's with the output of this new enhancement parsing logic, but plan to do so in the next few days. I'm still combing over the generated data to sanity check it. So far though, it finally looks good. * To be fair, the tooling does tag effect groups with useful names but they don't always map cleanly / directly to enhancement naming standards, especially once we get into non-boost templates (procs), global effect and so on.
  4. At least for the proc, I'm inclined to think this is a simpler bug than the one in the linked thread. I am treating target.isFriend? as an indicator of PvE, and I honestly can't explain why I chose to do that. Using the logic explained in that thread, this ends up evaluating as "not PvE" which turns into "PvP". I'll have to make sure it doesn't cause surprising changes in other powers' PvP/PvE evaluation, but I think I can just fix that one by removing target.isFriend? from the list of things that indicate PvE. The issue in the proc aura is the same as the one in the other thread. I'm still pondering ways to fix that, and have an idea, but will need some time to code it up and see what happens. I'm not sure what I'm thinking of as a solution is do-able with the expression evaluation framework(s) I use currently.
  5. Fixed a long standing display oversight. Some powers have a collection of effect groups where one is defined as a "default" effect that will be only used if no other effect group in the collection triggers. The other groups might fail to apply because they had requirements that were not met, or they had chances to activate but didn't "roll" well enough to do so. The special group is called the "fallback" group. CoD always displayed the group, but confusingly displayed it without any information about this conditional behavior, making it look like it would always happen. There's now an icon on these groups with a pop-up text explaining this restriction. (The example here is from this power.) Thanks to @Bopper for noticing the oversight.
  6. Odds are good this isn't going to be fixed for a some time. CoD takes powers data in in a kind of streaming way. As each discrete chunk of data comes in, it's passed to logic that parses that particular kind of thing, with zero context. All logic that builds links between things that should know about one another (like a power knowing what AT's can use it) is done by later, whole-dataset passes that analyze everything and stitch the relationships together. To give you an example of what I mean, consider a power that is invoked only by redirection. It will often not be in either a power category or powerset associated with an AT (or critter). The only way to know what ATs will use it is to analyze every power (and every AT), find direct links between powers/powersets and ATs, and then detect indirect links between powers. If Power A is a power Blasters can use by direct AT/powerset relationship, and power A redirects to power B, then power B is also a power Blasters can use, even if there's no direct relationship. We can't do that kind of relationship analysis until everything has been loaded and a first pass on the non-relational parts of it done. So I can't know about the relationship between Blasters and Power B until I've loaded all the data for ATs, powers and powersets.* The PvP and PvE parsing of expressions is currently done in each attribmod as it comes in. The code that does this knows nothing about the enclosing effect group or the power which encloses that. All the code knows about is the expression it received, and a bunch of zero-context rules about whether a "piece" of an expression indicates PvP, PvE, or both/either. Fixing this bug requires better parsing of "not some critters" in a vacuum, or a second pass on all expressions to add context to PvP/PvE evaluation. Either one is non-trivial - adding "maybe PvP" to the context free parser would require a dramatic rewrite of it. Code for a "second pass" analysis of all the expressions doesn't exist and would need to be written. (And to be clear, a context-aware expression pass could get this wrong unless I improve the expression handler - imagine if this expression was on the effect group instead of something inside it.) Given how much of the time the current logic is "good enough" and I am working on other features, I don't have a huge motive to put in either version of that work to fix one effect in a single power. I'll noodle over alternatives that would take less effort, though. Someday I would like to improve this whole process and will likely rip and replace large parts of it, but probably not now. * This power-to-AT code in the original Rust code was buggy by the way, as it did not consider multi-step redirects between powers, which do exist in some player powers. Since the processing order of related powers is effectively random**, building a relationship mapping between powers would sometimes miss links because a power in a relationship chain was not yet seen. For example, if Power A calls Power B calls Power C, and you process C before you see B or A, then you will assume there's no relationship between C and A. I noticed this problem because I put the site's JSON data in source control, which let me see that the AT relationships for some powers were changing between runs of the extract code when nothing else was changing. Fixing this required added logic to perform the relationship analysis in multiple passes. ** Powers are stored in a hashmap as they are loaded, and most hashmap implementations make no guarantee about ordering. Even if you sort them, you don't know that you're sorting in an order that means you will process them in order of their relationships.
  7. This is a CoD data processing bug. Ruby's original parser code handles only some what CoD does. There is a lot of post-processing done on certain aspects of the resulting data. The PvP/PvE-ness of an effect is one of those things, and it is one of the more complex post-processing bits of logic I added. Some power effects are explicitly tagged when they are PvP-specific effects, and when that tagging is present, CoD honors that and does not do additional inspection. That process is simple and I wish it was all that was ever required. However, the vast majority of effects do not have this tag, and the "PvP/PvE" nature of an effect has to be inferred from expressions attached to the effect. When we can see that an effect says "if target is a critter and target is not a friend", this taken to mean that the effect is expected to happen in PvE. Conversely, having "if target is a player and target is not a friend" expression is taken to mean that the effect is PvP specific. (Note that the expression may not need to explicitly ask "is target (not) a friend" as the power has targeting info that (usually but not always) makes this obvious.) This conditional interpretation of powers' PvE/PvP nature is usually robust, but can and does fail because CoD does not have all the context that the game's combat engine does. The "if player / if critter" expression logic can be part of a much more complex expression, and other conditions in such an expression are simply collapsed to true or false based on some usually reasonable but potentially false assumptions, Also the interaction of "if player / if critter" with targeting constraints occasionally becomes very complicated. Most of this is simply to explain why the processing is complicated to start with. What's happening here, though, is a fairly simple breakdown in that logic. The expression here checks for whether an effect applies to any of a list of critter "AT"s. The test is "if not (critter or critter or critter or critter)", which CoD's parser turns into "if not (PvE or PvE or PvE or PvE)". So the parser is evaluating that as "not (PvE)" which means "PvP". This is clearly wrong, but because the expression is so explicit, given the data and assumptions the parser has to work with, it's an understandable outcome. It would be more accurate for the parser to realize that saying an effect only applies to "not some critters" still means it could apply to other critters, but given the way the parser is structured, looking at each part of the expression in a vacuum, adding that will be (very) challenging. This doesn't happen to the "large crit" expressions in Scrapper powers more often because, looing at most powers, they have this expression instead. if !((target>arch eq 'Class_Minion_Grunt') || (target>arch eq 'Class_Minion_Pets') || (target>arch eq 'Class_Minion_Small') || (target>arch eq 'Class_Minion_Swarm') || (target>enttype eq 'player')) That translates to "if not (target is critter or target is player)", which collapses to "if not (PvE or PvP)" which just flips the two states. It becomes "PvP or PvE", which CoD (correctly) displays as "Any". The parsing described here is done on the fly for each attribmod in a vacuum, but in the Bone Smasher example, there's a pretty unambiguous condition expression on the containing effect group that says "if target is a critter". CoD doesn't handle this nesting of conditions in its PvP/PvE logic. If it did so, this bug would be fixed. That's probably how I will try and address this particular issue.
  8. Updates with new features! There is now a "Set Conversions" page. This is similar to the "Boostset Groups" page, but lists sets by the conversion "group" they are part of. One the conversions page you can choose one of the sets in that group that you'd like to see the conversion options for. When you pick a set to convert, you get additional controls for things like what level of enhancement you want to convert and whether you're converting an attuned version. Attuned versions always convert as though they are the lowest level available in the set, so you lose the slider if you enable this (or if the set exits only as an attuned set, like ATOs). As you change things, sets in the conversion group that are ineligible as conversions you could receive turn red. When a conversion is selected, levels ranges also pop up next to the list of sets, to help make clear why they turned red. The controls and the set / conversion lists default to a wide, desktop browser friendly layout but will collapse vertically on narrow screens. On the "Boostset" pages: The "Member of:" line is now a link to the appropriate Boostset Group page (meaning you can go right to a list of other sets in that group). The "Allowed Conversions" entries are now links to those "Set Conversions" pages. On the "Boostset Groups" page: The list of groups on the bottom of the page finally sorts top down then across instead of across first then down. The lists should still collapse vertically on narrow devices. Having them do this was the only reason I accepted the old sort order (which I found super visually unintuitive) for so long. I finally found a way to make it both work on narrow screens and sort down then across. (Embarrassingly, doing what I always wanted was actually simpler than what I was doing before...) This same "fix" is in use on the new "Set Conversions" page. The idea behind the set conversions pages and the conversion controls are to allow you to easily see what a set can convert into, in order to make it easier to find smart conversions (or avoid ones with poor odds or poor chances of market returns). Separately, I stumbled across (and fixed) an old bug in the Rust bin parser. It deals with very internal details of how the game code looks up text. Due to bugs over CoH's lifespan, a lot of you probably have some familiarity with "P-Strings". These are things like P2315351 - they're used as placeholders for "real" text, mostly useful to keep from repeating the same text in lots of places. While reading most bin files, both the game and the bin parser find these placeholders instead of the real text and have to have to look up the actual text in a big lookup table that itself is stored in another bin file. You end up seeing the "raw" placeholder when it can't be found in the lookup table where the text for it should be found, which used to be really common because the Cryptic and even Paragon devs had kind of crap tooling. P-Strings get used for "dynamic" stuff, where you have lots of the same "thing" with many different incarnations. Think of things like a power's description, a missions' text or an NPC's dialog. These are things where the texts are created by powers devs or content writers working on those things. Very roughly, the P-Strings are generated from this content by tools that parse it for later building into bin files. But a lot of things in the game are much more static - think things like drop-down or pop-lists menus, or some of the fixed text on various screens. That stuff also gets a keyed lookup, but it's not a dynamically generated P-String. Instead it's a fixed lookup string, probably hand-rolled by a dev. The map from this key to the text is maintained in a flat text file that also gets fed into the bins. The conversion groups for boost sets use these "fixed" keys. "Rarity: Uncommon" is mapped to lookup key ECUncommon. (I presume this stands for "Enhancement Conversion Uncommon".) The other conversion names have similar keys. It turns out that some of the places these keys are defined have different case than the way they're referenced in the game's data. One conversion group was defined as ECPvP, but used everywhere as ECPVP. It seems CoH doesn't care about the case of letters in the lookup keys, but the bin parser did. Believe me, I spent way more time figuring out what that problem was than it took me to actually fix it. I was so confused why some conversion names were correct and some were "raw". It's fixed now, and it probably changed a small number of other things in the game's data. This includes the "raw" data archives (since they basically come right out of the bin parser), so you care about those, grab them again.
  9. I found and fixed an obscure and fairly long-standing bug that was due to a few critter powers having periods in their internal power names. Previously I had assumed that periods were used as separators between power category, powerset name and power name. Where necessary, I would split "full" power names on periods and pick the last element as the power name. However, a very small number of critter-only powers actually have periods in the power name, causing that heuristic to produce strange results. In one case, the power name ends with a period, meaning splitting on periods and picking the last bit meant the power had a blank name, resulting in a power data file called simply .json. The affected powers were: v_arachnos.explosive_drone.intangible. v_security_guards.security_guard_advanced_assaultrifle_butt.adv._assaultrifle_butt v_security_guards.security_guard_advanced_submachinegun_butt.adv._submachinegun_butt Yes, that first one's internal power name is "intangible dot". That means its "correct" filename for CoD's purposes is intangible..json. (Two dots.) These are the powers' internal names, which for critter powers (especially pseudo-critters like bombs or patches) are often quite different from their display name, if they even have one. This is why I rely on the internal names to create CoD's data files, since using the (sometimes empty) display names would lead to at least very confusing or at worst overlapping power names. It was a little painful to find and correct all the places that CoD's code assumed it was safe to split blindly on periods, but I think I did so. Usually the correction was to split a fully-qualified power name no more than twice. (This still assumes no powercat or powerset name will have a period in their internal name.) Often the correction was simply to not bother splitting the name when I know I shouldn't need to - usually because I know I'm working with a power name. This unnecessary splitting being done in like 5 places, which is a teeny, tiny bit of the codebase. It should be noted that this bug did affect the "raw" JSON power files as well as the massaged ones used by the site to display powers data, so if you are using the "raw" files and had the latest versions you might want to download the "raw" archive(s) again.
  10. CoD's data files and code have been updated. There should be no visible changes to how it displays things, and no live data should have meaningfully changed. I briefly broke the "Attribute Tables" page, but it's working again now.
  11. While there are no outwardly obvious benefits from this yet, I can now (re)generate CoD's data significantly faster than I used to. With the old code, building a full dataset for the site used to take about 10 minutes. I would often start it and leave the room to do something else for a while. Now it takes about 2 minutes. This is due to a combination of things. Code changes mean CoD's ingestion of data from the Rust language bin parser sped up dramatically. Code changes mean CoD's writing of JSON data out of Python sped up a little I have a new home computer. My old one was about 11 years old. While I bought the same nominal model of Intel CPU, it's 11 generations newer. I run my CoD development in a Linux VM, and that VM is running from an SSD. It did on the old computer too, but it was a SATA attached SSD running from a USB3.0 dock. The new system has the OS and any VMs running from internal NVMe SSDs. which have something like 5x the sequential write speed before considering the old drive was USB attached. Edit: I also upgraded the version of Python in use from 3.8.2 to 3.11.1. The 3.11 version of Python had some significant speedups, and in the general case it's about 15% faster. Note that this would only affect stuff in CoD's codebase that's pure Python (of which there is a fair bit). The code changes were because I did finally come across a data serialization/deserialization library for Python which I had not seen before and which was worth gutting the code to swap it in. The new library has excellent speed compared to the library I was using, which I knew was among the slowest. The new library is much simpler to write code for. I reduced the data model codebase by about 50%. The new library calls for the use of "type hints". More on that below, but this is something I wanted to add to CoD's Python codebase for a long time but the effort wasn't worth it without something like this to motivate it. The new library interfaces with one of the fastest JSON parsing libraries available to Python. I was using the 2nd fastest (depending on benchmark) previously, so not a lot changed here, but the seamless integration in the code is nice. Basically this really speeds up debugging, especially for code that doesn't run until all the game data is parsed and ready to use. You can imagine the annoyance in debugging such code previously since I hadn't gotten around to adding any "extract just this bit of the data" logic. It also helps since I plan to add more data extracts / transformations - those will add to the run-time, but now adding to a much smaller base. Re: "type hints" - like most mainstream languages, Python is a "typed" language, meaning objects are of specific "kinds", where their kind determines what you can do with an object. You can multiply numbers, capitalize strings, sort lists, and so on, but you can't sort a single number, capitalize a list or multiply strings. But while Python cares what objects are and can do, it doesn't generally care where you store them. A lot of languages are "strongly typed" and require you to say (for example) "X is a variable that you can only put integers into." Python is like, whatever, man, you can store anything anywhere. Which is great for fast prototyping but not always great for complex codebases where you might assign the wrong kind of object to a variable, and Python won't complain until you try to ask the thing in that variable to do something that it can't. For this reason, strong type requirements are popular, even for languages that don't usually support them. ("Typescript", for example, is a strongly-typed variation on JavaScript that compiles to valid JavaScript code.) Python got on this bandwagon a while ago, and recent-ish versions added a way to specify variable types in the code. You could do before using specially formatted comments and tools that understood how to read them, but these new "type hints" are accepted by the Python interpreter itself and pretty clearly aren't something else (like a vanilla code comment). Python itself doesn't actively do anything with type hints - you could label your integer's "Potato" and it would not care. But Python does update the the compiled code with the type information so that other tools can use it to check the code for correctness in how it uses variables. Well, that's the main intended use. The new serialization/deserialization library, for example, uses them to know how to transform data. Which is a very handy way to achieve two useful things in one place.
  12. If you check the linked page, there's no damage included, energy or otherwise. Not even for the linked "sub effects".
  13. You're right! It looks like I was looking at their display names and not their internal powerset names. "Hybrid_Silent" displays as "Hybrid". Similar thing with "Interface". So with that cleared up, I see no problem with your suggestion.
  14. If all you want is the raw list of the entire powercat by AT, sure, that's easy. I'm not very happy with it as a UI though, because it just gives people a raw dump of everything in each Incarnate powerset in no particular order. Some of the powersets are worse than others in this regard. Hybrid is especially gross, containing a ton of "sub powers" that obscure the main powers characters would actually own. Given that the other per-AT power lists are much more specific, I think most people would find that surprising and, honestly, not that helpful. Sure, it's more helpful than not having any link at all, but I'd rather make the links be to more helpful list than that.
  15. Just as some background, all the linked things we have now are linked because there's an explicit thing I can search for in data that makes the link between an AT or a power explicit. For example, the ATs all have a field that explicitly names the primary and secondary pools for that AT, and also lists all their available pools. (Presumably, at some point, somebody at least considered the option that different ATs could have had different pools available.) Epic powers flip the script a bit, containing expressions that define who can access them. There's no equivalent to this in the Incarnate powers. Obviously we would never expect to find any AT associations, since that's not how the system works. But there are no requirements. It'd be handy if there were - I could use that to say "hey, this power has some kind of player requirement, so that must mean a player can have it - I'll add it to a a list based on that. But no, there's nothing like that. At least not in the powers themselves. I'm speaking without checking, but I'm gonna bet that this is because the "link" is in the crafting recipes. If a power is something a player can own, it's because it's granted to them by crafting it. Thus, the way to dynamically know a power is one a player can directly own is by finding it as the reward in an incarnate recipe. Conveniently, parsing recipes is one of the things I've been (very) slowly working on. However, like I said, for now I could just hard-code a list for now. I like for everything on the site to be data driven, but it's isn't all like that. The landing page with the AT links on it for example is totally hand-crafted. I think I can split the difference here - "manually" extract (or get a kindly dev to share) some data once and use that generate a list that I can use to render a page of obtainable iPowers.
  16. Also: Hi, I'm back! I kind of disappeared from all sorts of gaming-related stuff (which is really only CoH for me) over the holidays. Lots of work going on with the house, lots of stuff going on with my mom (she had a severe stroke and is pretty much gone without having died biologically), then holiday hosting, work and whatnot. Oh, and then I built a new main home computer. Still working on getting that fully set up with all my dev capabilities, but it's like 90% there. Which is going to be way more than 100% of what I used to be capable of, because my old rig was 11 years old. 😝 Other than the "mom had a stroke" thing, everything's good, but I've just had no time to spend on CoH / CoD. That should get better again soon. 🤞 The only time-consuming thing in my immediate future is going to be tax season. For all the right reasons, filing my taxes is going to suck this year. We're talking like it taking a weekend, though, not a week. My wife has been using a tax preparer since before we got married, and next year we'll be filing jointly, so this is the last year I'll need to deal with that. 🎉
  17. Maybe... Is what you're looking for just a big list of everything in the Incarnate powercats? That would have a ton of stuff in it. I'm not worried about it technically or anything - it just doesn't sound super useful. But I think it would be easy to build. Or are you looking for something more like a list of the "top-level" power that we think of when we click on the powers? The only issue there would be that it might have to be maintained by hand. The organization of stuff in the incarnate categories is seemingly random, and I'm not sure they're anything native to their data that lets us actually identify the ones we consider the top-level power. I'll take a look. We get new Incarnate stuff infrequently enough that maintaining such a list manually isn't the end of the world, but doing it initially would be a bit mind numbing.
  18. Hrmph. This is probably going to trigger a mini project I've been able to avoid. Most of the distinct visual "widgets" you see on CoD pages are distinct modules of code, and have their own sense of state and programmable behaviors distinct from other things on the page. Individual attribmod rows under each effect group are not like this. Effect groups are, but attribmods in the groups are not. As a refresher, the rough logical hierarchy for powers looks like this: Power | +---EffectGroup | | | +-----Attribmod | +-----Attribmod | ... +---EffectGroup | | | +-----Attribmod | +-----Attribmod | ... ... Similarly, the panel on each CoD powers pages labeled "Effect Groups" contains one "widget" for each effect group. It is, in turn, composed of smaller, specialized widgets, such as: all the icons for each group, all the icons for each attribmod in the group (which appears once per attribmod in the group), and any nested effect groups (meaning the effect group widget can display other effect group widgets to arbitrary nesting depth). But what is not a widget of its own is the place where each attribmod's info is displayed. Instead that's just part of the Effect Group widget, which renders one row of info per attribmod in the group. This was mostly fine (but never awesome) when I was displaying simpler stuff in each row. But now that CoD is more complex, partly due to better understanding on my part and partly due to new features in the powers system, I find myself wanting each attribmod display to be a widget. That would let it hold state and remember what details it has already rendered. Right now if anything needs to change I re-render the whole effect group. And if I am changing one, I am probably changing them all. Now, that probably sounds bad, but it's not terrible - most powers don't show that much info. But what made me really notice this (mentally, not visually) was that if I want add a control somewhere on the page that lets you control how "tick-mods" are displayed, the only way to update any of them is to refresh all of them, whether they have any "tick-mods" or not. That withers my developer soul a little. Now, that said, this is how changing the AT dropdown or level slider have always worked. When you change them, every effect group is re-drawn. But that feels less awful, since changing AT mods or level values really changes what a lot of attribmods need to display. Anyway, I'm mostly just "stream-of-consciousnessing". I may just suck it up and do this the less fancy, less elegant way, but I'm tempted to spend a bit more time now making it easier to work in new attribmod changes in the future.
  19. Not native to the site, no. You'd need a way to search by value on attribmod fields which would be crazy to try and index for use in the browser. (Remember, there are no logic servers for CoD - everything is done in your browser based on pre-prepared data files the web pages pull in.) However, if you're handy with searching text files, it's possible to find it in the raw data. This is actually how I checked for powers to look at when updating the site. I like RipGrep for this sort of thing. $ rg 'f_tick_mag_additive' | rg -v ' 0.0,' powers/mastermind_pets/zombie_minion/summonarmor.json: "f_tick_mag_additive": -0.013199999928474426, powers/mastermind_pets/zombie_minion/summonarmor.json: "f_tick_mag_additive": -0.013199999928474426, powers/mastermind_pets/assault/conserve_power.json: "f_tick_mag_additive": -0.0027000000700354576, powers/mastermind_summon/mercenaries/serum.json: "f_tick_mag_additive": -0.008799999952316284, powers/mastermind_summon/mercenaries/serum.json: "f_tick_mag_additive": 0.06599999964237213, powers/mastermind_summon/mercenaries/serum.json: "f_tick_mag_additive": -0.02199999988079071, powers/mastermind_summon/mercenaries/serum.json: "f_tick_mag_additive": -0.002199999988079071, powers/mastermind_summon/mercenaries/serum.json: "f_tick_mag_additive": -0.002199999988079071, $ rg 'f_tick_mag_multiplier' | rg -v ' 1.0,' $ That first command says "look for files containing lines with the string f_tick_mag_additive that don't contain ' 0.0,' (the default value of 0.0 with a leading space and a trailing comma)". It found 3 powers (it lists Serum multiple times because there are multiple different additive things in there.) The second command looks for files containing lines with the string f_tick_mag_multiplier that don't contain ' 1.0,' (again the default with leading and trailing markers so we don't get substring matches). There are none of these so far.
  20. Data is currently uploading, then the site code will be updated. Call it 30 minutes from this post. As always, let me know if you see strange and/or broken things.
  21. So one of the new features in the powers system is the concept of "accumulating" changes on attribmod values. These change the current value of an attribmod by a small amount every server tick. Currently this is used in a few Mastermind powers (or MM pet powers) to create "decay" mechanics on buffs so that the buffs decrease over time. There are two base versions of this - additive changes and multiplicative changes. The additive changes create linear change, while the multiplicative ones create compounding changes that decay or grow on a curve. Technically a single attribmod can have both multiplicative and additive per-tick changes applied. All the current ones are additive only. The unit of time change on these is one server "tick". That's roughly 0.132 of a second, but that depends on how well the server is getting things done. Every time the game server updates things on entities in a zone, these per-tick accumulations are updated by the given amount and operation. Right now I have a fairly primitive display of these values - I am just displaying the raw number that's used to update the value per tick. Given how fast ticks are and how long most effects are meant to last, these numbers are quite small. It's not that helpful of a way to display it. I do plan to display a more useful number, but at least this gets it out there. I'm open to suggestions on good ways to do this. I am currently thinking (after confiming what a server "tick" should be) of displaying the additive changes as a "X% per Y seconds" value, with multiplicative values displayed as "decays/grows to X% of base after Y seconds". I can still display the raw value too.
  22. Yeah, I am not sure if I can fix that without maintaining some sort of exception list. The "context free" way CoD tries to figure out whether something is PvP, PvE or either sadly depends a lot on allowed targets. There are actual PvP flags that mark an effect as PvP only, but that's not used everywhere, and it being achieved via player/critter target specificity is really common.
  23. I'm behind on getting the latest page updates working. I got the bin parser and site builder working. There a handful of bin format changes scattered around various data structures, and while none of them were complicated, it took me longer than it should have to track them all down and account for them correctly. I finally got it fully working this morning. I now just need to update the site to display new fields and upload the new data. I do expect this to be done by no later than this evening US/Central time, hopefully sooner. I may have placeholder icons for a couple of new attribmod flags for the time being.
  24. Something to bear in mind: if this change specifically causes certain content to be significantly easier because that content just happens to ride level boundaries that suddenly get powers they never used to, it's actually feasible for the HC crew to tweak the content to account for it, rather than avoid the change. This could be relatively simple stuff, like tweaking just the main bosses/AVs in a TF, tweaking the level transitions for the critters in it (say, bringing some scarier mob versions that only appear at higher levels down 5 levels or something), or just adding a new boss type here and there. I'm not attempting to trivialize this kind of change, but HC has some fairly active content devs. As long as such chances can be targeted just at specific content, I think it's feasible without being a big resource drain. I point this out because the arguments against this seem to center around certain, specific TFs because they happen to lay at level ranges where some meaningfully potent powers come into view that were not before. That doesn't sound like a wildly sweeping problem. Sure, it will also affect any missions in the same level band, but I think that's far less of a meaningful thing for your typical arc - mostly because of TF merit rewards. Even if moving of powers down somehow exposed new crazy farming missions or similar exploit-y things that never mattered before. that would still be something that can be fixed in a targeted way. I'm a huge fan of the T2 secondary change. I like the idea of the other stuff moving down so that we don't have to fill levels up with pool powers so much, but I wouldn't keel over if we didn't get it. I'm salivating over the T2 secondary one, though, and don't think any power creep it introduces (mostly at very low levels) is worth sweating.
×
×
  • Create New...