Jump to content

Dev Diary - Knock, Knock...


Number Six

Recommended Posts

  • City Council

Hello, heroes and villains!

 

Some of you know me already, but for those who don’t, I’m Number Six, Homecoming’s lead for what we call the ‘code’ side of the development team. So not the outwardly fun stuff like powers and missions - though I do have some involvement in those - but the boring and technical things like engine development, user interface, data processing, etc. Basically anything that involves actual compiled program code goes across my desk.

 

Today I want to talk about something that is near and dear to many of your hearts, or in some cases, hated with a fiery passion: Knockback. While it may be sometimes controversial, this game mechanic is not only iconic in the super genre in general and COH/V in particular, it’s also the vehicle for one of the more fun new toys we’ve developed for the content developers - the ‘data’ side of the team - to play with.

 

As some of you may have noticed, a while back we quietly and without much fanfare slipped in an effect that had never been seen in the City before: Gravity Control’s singularity pet was changed to pull enemies towards it. This kind of ‘reverse knockback’ or ‘negative repel’ is something that had long been asked and theorized about, often in the context of crazy ideas for how to implement it with various hacks like spawning dozens of carefully positioned invisible pets.

 

Those with even sharper eyes may have noticed all the way back in April 2020 when, for a day, Brawl was sending its targets flying in all sort of random directions.

 

Both of those were tests of a new engine feature that we developed in February of 2020 that has a lot of exciting potential, far beyond simply sucking stuff to a central point. It gives power designs a new level of flexibility they never had before, and quite literally changes the game. Far from being just a new feature, the vectored knock system replaced the existing knockback mechanics entirely, which is part of why we were extra cautious about rolling it out and wanted to make sure it didn’t change the ‘feel’ of knockback in any way.

 

Now that it’s been well over a year since the system was in place and nobody noticed the difference, we’re starting to see content that takes advantage of it emerge from the development pipeline. I’ll cover it in more detail further down, but the new system is used quite a bit in the new Strike Force and powersets being rolled out in Page 3. In this series of posts, I'll do a deep dive into the development of this feature and some of the technical underpinnings of how it works.

  • Like 16
  • Thanks 9
  • Thumbs Up 6
Link to comment
Share on other sites

  • City Council

Part 1 - A History Lesson

 

Before going too deep into how vectored knock works, let’s take a moment to rehash the mechanics that were in place for many years. Historically there are 3 of what we call Attributes that are of interest here:

 

    kKnockback

    kKnockUp

    kRepel

 

Since these are standard attributes, they have a numeric value associated with a character -- by default everybody’s attribute for these are ‘0’. KB effects increase the value of your Knockback attribute, KB protection effects are just a negative magnitude effect that keeps it from going above 0. Incidentally, that’s why the commonly suggested ‘negative knockback’ couldn’t work; because negative knockback is just KB protection that you already get from a number of sources.

 

Knockback is the most common of these effects. If the magnitude of the Knockback attribute ever gets above 0, an entity is Knocked -- some velocity is added to them and they are put into a special animation. For NPC critters, that can include going into ragdoll mode.

 

The direction of the knock comes from the game remembering the last entity who hit you with a knock effect, this happens because effects very frequently have some amount of delay on them to wait for animations to play. That can cause some rather amusing artifacts if one of both of those entities moved a long distance between when the power was activated and the effect actually hits. The distance of the knock is calculated based on the magnitude of the effect, and the game also adds a surprising amount of calculated upwards velocity to make the target sail in a visually satisfying arc.

 

Knockback also comes with a special case built into it. kKnockback attribute values that are above 0 but below 0.75 instead result in Knockdown, which plays a different falling-over animation and does not add any velocity or ragdoll. One well-known quirk of this mechanic is that if two separate Knockdown effects hit on the same combat tick, the combined magnitude may well exceed 0.75 and get converted to Knockback instead.

 

KnockUp -- go on, get your giggles out and then get your mind out of the gutter -- is an entirely different attribute that works very similarly, but handles only upward movement. You may notice that KB protection powers actually provide both KB and KU protection separately. There’s not much to say about KU other than that the moment of velocity it imparts is calculated based on a different formula, but still based directly on the final magnitude of the effect (after KU protection is subtracted).


Repel may seem very different at first, but is mechanically quite similar. Most of the difference in Repel effects don’t come from the attribute itself, but instead from how powers conventionally use it. The primary mechanical difference is that Repel does not make the target play an animation, and it pushes in a straight line away from the source instead of doing math to try to curve the arc. From a powers perspective, Repel effects usually have a duration and apply continuously, while Knockback effects are typically a 1-tick impulse. However, there’s no reason Repel couldn’t be used to give a sizable brief shove instead.

  • Like 7
  • Thanks 2
  • Thumbs Up 2
Link to comment
Share on other sites

  • City Council

Part 2 - Visualizing the Change You Want to Be

 

When I first began thinking about how to do something along the lines of reverse knockback, I decided that we needed to plan something that would be flexible and future-proof.

 

A very early proof-of-concept prototype was done that added two new attributes, called kKnockIn and kAttract, just to test the concept. Those attributes worked exactly like Knockback and Repel, but with the source and target entities swapped.

 

Those attributes were never intended to be anything more than a proof of concept, and indeed never even made it out of a development branch. Somewhere gathering dust I have a copy of Assault Rifle with an M30 grenade that makes big groups hilariously get flung right on top of you. There were obvious problems with that approach, the least of which being the annoyance of having to fill out class tables for these new attributes for 10+ archetypes, add them to every KB protection power or enhancement in the game, etc.

 

Ultimately though, I thought that we could do better. There weren’t any real tools for moving entities around from powers other than Teleport (and ForceMove but that’s terrible, see the afterward), and I could think of all sorts of interesting things that could be done if the designers had more control there. So then came the brainstorming.

 

After a lot of design revisions and bouncing ideas off the team, we came up with the sketch for the Vectored Knock system. It would be built on Effect Parameters - an innovation from the Issue 25 power system revamp that lets different effects take any number of arbitrary parameters in an efficient way - and would let designers specify not just the direction of the knock, but also fine-tune exactly how the velocity is calculated, so that the strength of the effect would not necessarily have to be tied directly to the magnitude. A priority system was also devised to give us the ability to decide exactly what happens if multiple conflicting effects are applied on the same tick.

  • Like 10
  • Thanks 3
  • Thumbs Up 1
Link to comment
Share on other sites

  • City Council

Part 3 - Anatomy of a Power

 

With all that history out of the way, I’ll jump straight into the design. Here’s a copy and paste from the documentation for how to use the new effects:

 

Effect {

    AttribMod {

        Attrib kKnock

        Scale [num]

        Params Knock {

            VecStart [Anchor]

            VecEnd [Anchor]

            AdjustPYR [pitch] [yaw] [roll]

            Priority [integer]

            Vel [num]

            VelMag [num]

            Height [num]

            HeightMag [num]

        }

    }

}

 

A few bits of context here.

  1. kKnockback was renamed to kKnock, though the old name was retained so powers could be loaded without changing them immediately.

  2. kKnockUp was deprecated. Now that powers can specify what direction they want to knock something, having a separate attribute for it became wholly redundant. It still exists for compatibility reasons, but will eventually be fully replaced by kKnock effects and removed.

  3. The Knock parameters above also work for kRepel effects.

The important part of that structure are the VecStart and VecEnd parameters, they put the vector in vectored KB. A ‘traditional’ knockback would use VecStart Source, VecEnd Target. A ‘get over here’ grappling hook power would use VecStart Target, VecEnd Source. VecEnd also accepts things like Up, Down, and Facing, which is where the KnockUp replacement comes in.

 

The ‘Down’ vector is especially interesting, because it allows for the creation of powers that cause Knockdown but have a high magnitude and can punch through KB protection. This is something that was not possible before, since a high magnitude would normally mean a long knockback distance. Knockdown powers with a ‘down’ vector also cannot merge together into KB and will always stay as Knockdown.

 

AdjustPYR is also quite a bit of fun and was used in the April Fool’s Day Brawl. After the knock vector is calculated, that setting can be used to rotate the vector along an axis and point almost any direction you can think of. Imagine a sweeping strike with a Titan Weapon that knocks the target left. Or a Whirlpool that uses vectored repel to actually drag things in a spiral.

 

Priority is used to disambiguate effects that happen on the same tick. The new system is fairly smart about it and unlike the old one that could only remember a single source, it now merges multiple vectors together, so you end up with a final direction of everything averaged together. But if you wanted to make a power that takes precedence over everything else, a designer can do that by setting a higher priority.

 

The last 4 are for fine-tuning the velocity of the effect and just how much of it is derived from the magnitude, as well as doing the simulated arc that traditional knockback effects have. Back to the design doc, the defaults that correspond to each type of effect are:

 

kKnock (aka KB): Vel = 1.0, VelMag = 0.025, Height = 3.0, HeightMag = 0.25

kKnockup: Vel = 0, VelMag = 0, Height = 6.0, HeightMag = 1.0

kRepel: Vel = 0.5, VelMag = 0.2, Height = 0, HeightMag = 0
 

Velocity is in world units per tick, being roughly feet per 1/30th of a second. Val is a fixed constant, while VelMag acts as a multiplier on the magnitude from the kKnock attribute. Height is a fun one, having a Height is what simulates being knocked in an arc. It’s also… complicated so I’ll just snip part of the design doc rather than try to break it down.

 

kmRr30XOJkGTSbR07Zpjf8ON3nIT1nUzv4U2c56o6p1-0g0NXjX3ilP0y2stgSemXn0czNJzpeTBVuwuETCQ8VvKHw8PklXNkJ_74k2qXEfmSvGRCul2UClMQu8-FR8YsvDre_DQ

 

A lot of math for something that we take for granted.

  • Like 9
  • Thanks 2
  • Thumbs Up 2
Link to comment
Share on other sites

  • City Council

Part 4 - Pull in Practice

 

The first player-facing application of the new tech was the Singularity change. This was chosen because it’s not an extremely common powerset and would let us evaluate it at a small scale. Being a pet power it would also be more difficult to take advantage of if there was some bug that allowed it to be use exploitatively or for griefing, etc. The power def for Singy’s new trick looks like:

 

    Effect
    {
        RadiusInner 7.0000
        RadiusOuter 45.0000
        Requires enttype target> critter eq

        AttribMod
        {
            Attrib kRepel
            Aspect kCur
            Type kExpression
            Target kTarget
            Table "Ones"
            Scale 1.0000
            Duration 0.6250
            MagnitudeExpr 38 distance 7 - - 19 / dup dup * *
            Magnitude 1.0000
            StackType kReplace
            CancelEvents Teleported
            Flags IgnoreCombatMods
            Params Knock
            {
                VecStart                       Target
                VecEnd                         Source
                Vel                            0.0000
                VelMag                         0.1000
            }
        }
    }

 

That’s only the PvE version of the effect for brevity. It’s a fairly standard Repel attribmod but with the vector swapped from the normal direction, and the velocity calculation overridden. The magnitude expression here is to simulate a dense gravitational source and translates to 

((45-dist)/19)^3. In other words, the pull is very strong near the event horizon and quickly falls off to very weak for targets further away.

 

We learned some valuable lessons from this, including finding out that players teleporting while under the effects of a Repel effect caused all sorts of terrible rubber banding. That particular bug in motion prediction predates the vectored implementation and has probably been around for as long as Repel has, but it was never noticed because teleporting while being repelled was such a rare occurrence. Once the pets of Family bosses had access to it that changed very quickly. The same bug affects Knockback, but since KB effects only last 1 server tick it’s even harder to trigger there.

 

The same effect appears on a larger scale in Dr. Aeon’s Strike Force under conditions that I won’t reveal because it’s a spoiler, but it plays a role in a particular boss fight and draws all the players in to a big portal during one of the phases. The motion prediction problem with teleport turned out to be a blocking issue for that encounter, and so the bug is fixed in Page 3.

 

There are a few more subtle uses of the tech in the upcoming update. Seismic blast has a knockdown patch that uses a down vector to avoid becoming knockback when effects get stacked. Scrapper/Stalker Stone Armor’s new Geode power uses reverse Repel internally for better control over the position of the pseudopet that it spawns. Given how flexible the system is, I think it’s fair to say we’ll be seeing it used more as the powers team gets more comfortable with it.

  • Like 9
  • Thanks 4
  • Thumbs Up 1
Link to comment
Share on other sites

  • City Council

Afterward - What about ForceMove?

 

Some of you reading this may have dug around enough to be familiar with an unused special attribute in the code called kForceMove, and are thinking ‘Hey, wait a minute, why not just use that?’ For those who haven’t, ForceMove is a special attribute that does what it says on the tin and forces an entity to move to a specific location.

 

After about 15 minutes of looking at the ForceMove implementation it was clear that it would be a bad idea to use it for anything, ever. It’s obviously a very early work in progress meant only to test the idea.

 

How ForceMove works is:

If the target is a critter (NPC), it instructs the AI to move to that location. The AI constructs a path and walks there. It doesn’t even use wire movement, it just walks along the path.

 

Worse, if the target is a player - doesn’t matter if we’re talking PVP or a power you use on yourself - it sends a network packet to the client that tells the client to lock autofollow on the destination coordinates. Then the client tries to move there just like you had click-to-move turned on. The latency alone between the client and server’s view of the world makes this a bad idea, and I’m sure anyone who’s used autofollow while multiboxing is shuddering right now just because of how unreliable it can be.

 

There’s also the issue of targeting the ForceMove. The test powers that use it make use of another new feature called kPosition targeting which is a good idea, but also was still fairly early in the design process and there are a number of issues with the implementation. The biggest one is that the target location is resolved not at power activation, but rather at the moment the power is queued. For NPCs that’s not really a problem, but players queue powers all the time while they’re out of range or out of endurance or otherwise in a situation where it won’t actually activate for a long time. In that case, the location used for the power would be relative to the place where the player queued the power rather than where they were when it became able to activate.

 

TL;DR: The idea of ForceMove is interesting, and its best use case would probably be something like a “Charge” power that runs toward a target. However before that could happen the implementation needs to be scrapped and rethought.

  • Like 8
  • Thanks 8
  • Haha 1
  • Confused 1
  • Thumbs Up 2
Link to comment
Share on other sites

2 hours ago, Number Six said:

The magnitude expression here is to simulate a dense gravitational source and translates to 

((45-dist)/19)^3. In other words, the pull is very strong near the event horizon and quickly falls off to very weak for targets further away.

 

looking at all the selfies of hot imgurettes this morning. - Album on Imgur

  • Like 2
  • Haha 1

Get busy living... or get busy dying.  That's goddamn right.

Link to comment
Share on other sites

I am. 

 

I am in tears. 

 

WHIRLPOOL Y'ALL. 

  • Like 6
  • Thumbs Up 2

@Aurora Girl - Excelsior - BSOD
 Aurora Girl  (Blaster)- Energy/Atomic, Queen of Faceplants and former Mayor of Pinnacle Server  Straye  (Brute)- Savage/SR, Survivor of +4 ITF Nictus Crystals and Bobcat's Bane  Aurora Snow  (Corruptor) - Ice/Cold, AV Humiliator  Terraflux  (Controller) - Earth/Rad, Bass Exploder  Spynerette  (Arachnos Soldier) - Night Widow, Super Spy of Sneakiness and Stabbing  Snowberrie  (Tank) - Ice/Spines, Disco Ball and Lady of Winter

Link to comment
Share on other sites

15 hours ago, Number Six said:

Effect {

    AttribMod {

        Attrib kKnock

        Scale [num]

        Params Knock {

            VecStart [Anchor]

            VecEnd [Anchor]

            AdjustPYR [pitch] [yaw] [roll]

            Priority [integer]

            Vel [num]

            VelMag [num]

            Height [num]

            HeightMag [num]

        }

    }

}

 

excellent.

any room for a variable or little equation that could take (distance of knock) x (some type of damage component)?

because really, if we knock a minion far enough, we should not need to chase it down after it bounces off a stationary object.

 

thanks for the insights. luvyou1000

 

 

Edited by Troo
  • Thumbs Up 1

"Homecoming is not perfect but it is still better than the alternative.. at least so far" - Unknown  (Wise words Unknown!)

Si vis pacem, para bellum

Link to comment
Share on other sites

9 hours ago, Number Six said:

KnockUp -- go on, get your giggles out and then get your mind out of the gutter -- is an entirely different attribute that works very similarly, but handles only upward movement.

Oh, come on, that's not a "gutter" thing, that's the Miracle of Life.

 

And also the core mez mechanic of my proposed Gravidity Control power set. :P

  • Like 1
  • Thanks 1
  • Haha 3
  • Thumbs Up 1
Link to comment
Share on other sites

15 hours ago, Number Six said:

- but the boring and technical things like engine development, user interface, data processing, etc. Basically anything that involves actual compiled program code goes across my desk.

 

Sooo... the fun part. 

 

Gotcha! 🤘 👍

  • Like 3
  • Haha 1
Link to comment
Share on other sites

17 hours ago, Number Six said:

The magnitude expression here is to simulate a dense gravitational source and translates to 

((45-dist)/19)^3.

 

Okay, I know the answer is probably completely useless, but the power math nerd in my heart has to ask: Why 38 distance 7 - - 19 / dup dup * * and not 45 distance - 19 / dup dup * * ? Is there some magic where the - operator is removing non-negatives and resulting in distance 7 - being a minimum of zero, and that's what stops the magnitude from going off to infinity? Because if so, that's both terrible that it clamps out negatives that way, and also a fantastic hack to prevent infinite magnitudes, even though the inner radius 7 should do that anyway. And if not, that just seems like a really odd way to do the subtraction.

 

Actually, City of Data (the main view, or the raw power definition) shows (45/19 - distance/19)*(45 - distance)**2/361 but I'm assuming that's just weirdness with whatever processing he has to do to get the expression to not be in RPN. Same end numbers, though.

 

 

Oh, and as an addendum because I realized I hadn't mentioned it: Thank you for this entire post. As my group's resident powers/math nerd and City of Data Interpreter, I am super happy both for the explanation, and to see the work being done on improving how Knock/Repel work. I look forward to the day when you're hopefully able to have the KB-to-KD IOs just change the vector stuff, so a KD-ified power doesn't still knock Clockwork backwards. Because that would be amazing if you could eventually make it happen

Edited by BillyMailman
I failed to appropriately gush about how awesome this whole thing was.
  • Thanks 1

Pinnacle refugee. Powers and math guy.

Link to comment
Share on other sites

17 hours ago, Number Six said:

If the target is a critter (NPC), it instructs the AI to move to that location. The AI constructs a path and walks there. It doesn’t even use wire movement, it just walks along the path.

 

Always good to get a glimpse of the hamsters who keep this contraption running!  Thanks for the write-up!

 

On the quoted bit - this sounds like fantastic mind control.  Having an effect that declares "walk here" seems like a good way to add control to a thing that isn't your pet (which as I understand it, the pet entries themselves have the entry for commandable pet - not exactly ready to go on every mob we might sleep or confuse). 

 

If it turns a power into an MMs Goto command and doesn't have other tech hurdles anyway (and different pvp effect).

Link to comment
Share on other sites

9 hours ago, BillyMailman said:

 

Okay, I know the answer is probably completely useless, but the power math nerd in my heart has to ask: Why 38 distance 7 - - 19 / dup dup * * and not 45 distance - 19 / dup dup * * ? Is there some magic where the - operator is removing non-negatives and resulting in distance 7 - being a minimum of zero, and that's what stops the magnitude from going off to infinity? Because if so, that's both terrible that it clamps out negatives that way, and also a fantastic hack to prevent infinite magnitudes, even though the inner radius 7 should do that anyway. And if not, that just seems like a really odd way to do the subtraction.

 

Actually, City of Data (the main view, or the raw power definition) shows (45/19 - distance/19)*(45 - distance)**2/361 but I'm assuming that's just weirdness with whatever processing he has to do to get the expression to not be in RPN. Same end numbers, though.

 

 

Oh, and as an addendum because I realized I hadn't mentioned it: Thank you for this entire post. As my group's resident powers/math nerd and City of Data Interpreter, I am super happy both for the explanation, and to see the work being done on improving how Knock/Repel work. I look forward to the day when you're hopefully able to have the KB-to-KD IOs just change the vector stuff, so a KD-ified power doesn't still knock Clockwork backwards. Because that would be amazing if you could eventually make it happen

 

Billy, I cannot express how much joy this gave me. 😀

@Aurora Girl - Excelsior - BSOD
 Aurora Girl  (Blaster)- Energy/Atomic, Queen of Faceplants and former Mayor of Pinnacle Server  Straye  (Brute)- Savage/SR, Survivor of +4 ITF Nictus Crystals and Bobcat's Bane  Aurora Snow  (Corruptor) - Ice/Cold, AV Humiliator  Terraflux  (Controller) - Earth/Rad, Bass Exploder  Spynerette  (Arachnos Soldier) - Night Widow, Super Spy of Sneakiness and Stabbing  Snowberrie  (Tank) - Ice/Spines, Disco Ball and Lady of Winter

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...