CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
9.98k stars 4.08k forks source link

Explosion Scaling Formula Change #14033

Closed JoeKlesczewski closed 8 years ago

JoeKlesczewski commented 8 years ago

Since I'm not sure how to resubmit individual commits just yet, I'm making this an issue instead of a pull request for now.

In pull request #13913 it came up that currently explosions scale with an inverse factor ^ distance scale as opposed to an inverse distance ^ factor scale like in reality. Assuming a factor of two, at any rate.

@Coolthulhu gave as the reason for this that it makes for stronger explosions, but the difference is fairly minimal at the distances we see - at three tiles the realistic formula results in 11.111% (repeating) power while the current formula results in 12.5% power, and at five tiles the results are 4% and 3.125% percent respectively. This indicates that the current formula actually results in weaker explosions over long distance, though in any case the difference is, again, rather minimal.

For the sake of ensuring expected behavior for both contributors and users, I'd like to recommend that the formula used for explosion scaling be changed to the realistic one.

Coolthulhu commented 8 years ago

This is a very internal thing, not likely to really confuse anyone who isn't doing heavy code diving.

it came up that currently explosions scale with an inverse factor ^ distance scale as opposed to an inverse distance ^ factor scale like in reality. Assuming a factor of two, at any rate.

The factor is explicitly NOT inverse square distance. We had inverse square before and it lead to explosions being very localized, with grenades barely covering the area of a car. This would result in grenades having to be "cooked" till the last turn or tossed in front of zeds. At the same time, the explosions were really safe beyond their epicenter - you could literally drop a live grenade at your feet and walk away with certainty that you won't get a scratch.

Now, grenades are currently heavily underbalanced, but with inverse square formula all explosions become weak really quickly. Consider a hypothetical explosive with power 100. At epicenter, it shreds most stuff, but 4 tiles away from it you don't even take 10 damage while naked.

at three tiles the realistic formula results in 11.111% (repeating) power while the current formula results in 12.5% power

The current formula isn't 1 / (factor ^ distance), it's just factor ^ distance. Factor is always between 0 and 1. This means that for a default factor of 0.8, the damage at 3 tiles is 51%, which is much more than 12.5%.

The current formula - base_power / (factor ^ distance) is like that because it started out (and still is) as a propagating "field" of explosion rather than an expanding ball with fixed shape. It was easy to describe the power of each next tile in terms of powers of its neighbors (or at least the one with the highest power).

If you still want to change it, make sure you change all the formulas. A tiny bit of subjective realism in the code isn't work having discrepancies in formulas.

Then test it heavily or at least do enough math.

Currently used factors are (as far as I remember):

JoeKlesczewski commented 8 years ago

The factor is explicitly NOT inverse square distance. We had inverse square before and it lead to explosions being very localized, with grenades barely covering the area of a car. This would result in grenades having to be "cooked" till the last turn or tossed in front of zeds. At the same time, the explosions were really safe beyond their epicenter - you could literally drop a live grenade at your feet and walk away with certainty that you won't get a scratch.

Consider a hypothetical explosive with power 100. At epicenter, it shreds most stuff, but 4 tiles away from it you don't even take 10 damage while naked.

This strikes me as okay - with a better fragmentation implementation, we don't need to rely on the actual "blast" being the primary source of damage. In real life, fragmentary explosives are generally more damaging than concussive ones anyway - so it would be a move further towards realism, too. If there's not enough fragment damage being done, that's something that can be fixed. More on this below.

The current formula isn't 1 / (factor ^ distance), it's just factor ^ distance. Factor is always between 0 and 1. This means that for a default factor of 0.8, the damage at 3 tiles is 51%, which is much more than 12.5%.

Sorry - I didn't choose my terms well. A factor of 0.8 yields 0.8 ^ distance which can be thought of as 1 / (5/4) ^ distance. When I was talking about a "factor" of two, I meant one that yields 1 / 2 ^ distance not 2 ^ distance. This is closer to how it's generally thought of in physics (i.e. inverse square and inverse cube rather than squared half and squared cube), you see. Either way works I guess, and if the system already uses a different way we may as well continue using it unless we want to refactor and guard instead for factors less than zero.

It is very interesting that the default factor isn't 0.5 (two, in the sense I was using it before). That indicates that there might be something else at play here.

As far as I see, the actual "blast" damage simply represents the shockwave of the explosion, which for most of the stuff in-game is fairly harmless after a pretty short distance. For instance, the shockwave from a (fragmentation) hand grenade (the kind that our "grenade" is) is going to do basically nothing unless you're right on top of it. The opposite would be a concussion grenade - quoting from Wikipedia on those:

In the case of the US Mk3A2, the casualty radius is published as 2 meters (6–7 feet) in open areas

As you can see, even modern concussive hand grenades are pretty minor in effect compared to what one might expect. This also gives us a point of reference for TNT, since the Mk3A2 contains 8oz of TNT, or about 0.23kg.

Currently, there are pretty much three classes of explosions in the game - fragmentary, concussive, and incendiary. The "fragmentary" class includes stuff like the plain "grenades" and ammo cookoffs which should spew their fragments pretty far but only do minor concussive damage. The "concussive" class includes stuff like the mininuke that are the opposite. The "incendiary" class includes stuff like Molotov cocktails that do their damage via fire. Landmines in real life come in both concussive and fragmentary types, the two being very different in nature and use. Cataclysm's mines seem to be a strange mix of the two - fragmentary but still buried. We should probably also address that, though it's a bit of a tangent.

The fact that our explosive falloff factors range from 0.4 to 0.9 is very strange from both a programming and a player perspective - that some explosives fall off more quickly than others is strange, and the effect gets much more significant the larger the explosion. Unifying this is probably a good idea. But to do that, we need to get the different classes I mentioned to work in the same terms.

What I would suggest is that we switch to inverse square falloff, massively increase the power of concussive explosives, and balance the other two somewhat separately.

For instance, grenades provide 12 power, 28 fragment explosions. Changing this to a very minor concussive strength (call it 5) and a very high fragment count might be reasonable if we go to inverse-square falloff, since it models the actual shockwave doing very little damage indeed while relying on the fragments to do the work. The current US fragmentary hand grenade is published as having a 5m kill radius and 15m wounding radius (for naked human targets in open areas), though it should be noted that both of those are the distances where there is a 50% chance of it happening. Since tiles are somewhere between half a meter and a meter on a side, 50% lethality is a good mark for a four-tile radius, while 50% injury should be good for a ten-meter radius. Unfortunately, we now run into the problem that grenades aren't generally thrown that far in Cataclysm, so pending an overhaul of that system we should scale this down to maybe 2-tile (i.e. 3x3) lethality and 5-tile injury. Assuming even fragment distribution along a "shell", there should be an eighth of the fragments hitting two tiles away. This gives us a point around which to balance:

Knowing n total fragments of p initial power at d distance from the epicenter, x total damage being considered lethal, c chance of a fragment hitting a creature on a given tile (0 <= c <= 1), and f(p, d) being the damage with which a fragment hits given p and d, a hand grenade should yield at d=1 the following (after simplification): x = c * f(p,d) * n / 4. To find c we just need to figure out what number means there is a 50% chance of a single fragment hitting when d=4, which yields 1 = c * n / 36 and therefore 36 / n = c. Substituting we get: x = 9 * f(p,d) * n. Basic zombies having 80hp, for simplicity's sake let's say that x=81. That lets us further simplify to 9 = f(p,d) * n. Once we have a fragment damage formula, we can choose the damage and power of a fragmentary hand grenade to match, though nshould probably be at least in the hundreds in this case. For an arbitrary fragmentary explosive, using a as lethality range and b as injury range, the following system of equations should hold (x is left a variable because I don't know whether we want to use the zombie-based x=81 I have above or a player-based value that would ignore limb damage):

x / a = c * f(p,d) * n / (d + 2) ^ 2
c = (b + 2) ^ 2 / n

All but the biggest shockwaves should be far less deadly even a few tiles away than at the epicenter and those biggest ones should pulp basically anything at the center. It strikes me that an inverse-square would be perfect for this, since it simply means the following would need to hold for an MK3A2-based handheld concussive grenade (using the same variables as above except for i (0 <= i <=1) to represent "casualty degree", the fraction of lethality to consider it a "causality", which I don't know how to translate into the game system): x * i = p / d ^ 2 (though because zero division we'd need to handle the case of d=0 separately as x * i = p).

Incendiary explosives are a very, very strange case. There's all manner of ways we can handle them, though, and whatever we do with the other two types can probably just be hacked to remove the explosion damage and use the power field to control the radius of the fire. Or we could just leave the current system of handling fire in iuse.cpp. Either way.

The current formula - base_power / (factor ^ distance) is like that because it started out (and still is) as a propagating "field" of explosion rather than an expanding ball with fixed shape. It was easy to describe the power of each next tile in terms of powers of its neighbors (or at least the one with the highest power).

I don't follow how that formula specifically enables such a process - the same process should work equally as well if it were base_power / (distance ^ factor) instead, no?

If you still want to change it, make sure you change all the formulas. A tiny bit of subjective realism in the code isn't work having discrepancies in formulas.

By "all the formulas" you're referring to the calls to explosion() as well as the function itself, right? Unless I missed some of the relevant sections.

Coolthulhu commented 8 years ago

As you can see, even modern concussive hand grenades are pretty minor in effect compared to what one might expect.

That was the case when the damage was inverse square distance. It made most explosives useless.

The fact that our explosive falloff factors range from 0.4 to 0.9 is very strange from both a programming and a player perspective - that some explosives fall off more quickly than others is strange

It's partially just because it works better for gameplay, partially because mines blow mostly up, not around.

that some explosives fall off more quickly than others is strange, and the effect gets much more significant the larger the explosion. Unifying this is probably a good idea.

Not without a good reason. Here realism goes rather strongly against gameplay, because it makes a great deal of explosives pretty much useless.

What I would suggest is that we switch to inverse square falloff, massively increase the power of concussive explosives, and balance the other two somewhat separately.

If you can balance it so that they don't become insta-kills on "boss types" point-blank, while still not becoming useless few steps away, you could try. But if it would mean that a hulk (or worse - tank drone) stepping on a concussive grenade will be blown to pieces, some other solution will be required.

Since tiles are somewhere between half a meter and a meter on a side

Tiles are as big as they need to be. There is no direct tiles-meters conversion. In this case it should be more about "what works" that "what would it look like quantified in real life numbers" because how how much quantification and simplification is involved here. Player can't take cover, zombies don't have body parts, getting a giant piece of metal through the leg won't kill humans etc.

Assuming even fragment distribution along a "shell", there should be an eighth of the fragments hitting two tiles away.

Currently it's random. And the target can be standing over the grenade (smaller target should be shredded, but a bigger one can tank some or all of the fragments). With the exception of the target in the middle (one standing on grenade), fragments can only hit one target. And later on in the development, the fragments will go up (and down) too.

All but the biggest shockwaves should be far less deadly even a few tiles away than at the epicenter and those biggest ones should pulp basically anything at the center.

There's a big problem with balance with this approach. It makes it so that the only good way of utilizing weak and mid-strength concussives is cooking them and throwing them in the last moment. It also makes them only good for eliminating single strong targets rather than being the AoE option expected from grenades.

(x is left a variable because I don't know whether we want to use the zombie-based x=81 I have above or a player-based value that would ignore limb damage)

It's a fair bit more complex than just ignoring limb damage - fragments have accuracy which can boost or decrease damage dealt. I think the current formula is so that they can't headshot, but can good hit or normal hit. This could be simplified. That is, if there is a good reason to do so.

Incendiary explosives are a very, very strange case.

For now balancing them isn't really possible because fire damage resistance isn't a thing yet. Fire will eat through power armor like it's paper.

I don't follow how that formula specifically enables such a process

More intuitive and "natural" (in the mathematical sense):

power = neighbor_power * 0.8;

vs.

power = base_power / ((distance_to_neighbor + distance) ^ factor);

Also, it started out like that because at first I wanted to implement concussion being more useful in enclosed spaces. That was rather complex to calculate elegantly with unknown (as in - any possible) environment shape so I scrapped that part, but the formula stayed.

By "all the formulas" you're referring to the calls to explosion() as well as the function itself, right?

I think explosion has one and do_blast has two. And documentation describes the current behavior, so that would have to be changed too.

JoeKlesczewski commented 8 years ago

That was the case when the damage was inverse square distance. It made most explosives useless.

Right - but if we switch to relying on fragmentation rather than concussion for most explosion damage, then that would be okay, no?

It's partially just because it works better for gameplay, partially because mines blow mostly up, not around.

Which means that mines would benefit from falling off quickly. Also on that subject, land mines IRL are concussive rather than fragmentary. Should we change the ingame landmines to reflect this?

If you can balance it so that they don't become insta-kills on "boss types" point-blank, while still not becoming useless few steps away, you could try. But if it would mean that a hulk (or worse - tank drone) stepping on a concussive grenade will be blown to pieces, some other solution will be required.

Zombie hulks have 480 hitpoints, while a zombie has only 80. Even if we wanted the concussive grenade to do a full 100 damage a tile away (which means doing that damage to all zombies on that tile, importantly), that would still only mean a epicenter power of 200. That means a hulk would need to be hit by three concussive grenades at full power to be killed by them. Though since we probably don't want a hand grenade to immediately pulp all zombies in a 3x3 area, we could probably drop that to 150 or 120 power - that pulps basic zombies at the epicenter, leaves them alive (though badly damaged) next to it, and considerably wounds them another tile out.

Tiles are as big as they need to be. There is no direct tiles-meters conversion. In this case it should be more about "what works" that "what would it look like quantified in real life numbers" because how how much quantification and simplification is involved here.

Certainly, but at the same time working off a rough internal scale is a good starting point. Like I mentioned, "real life" values would be horrendously big on the scale I was working on, so I reduced them.

Currently it's random. And the target can be standing over the grenade (smaller target should be shredded, but a bigger one can tank some or all of the fragments). With the exception of the target in the middle (one standing on grenade), fragments can only hit one target. And later on in the development, the fragments will go up (and down) too.

Yeah, this causes one of the problems I'm trying to fix - as it stands, a fragmentary grenade can only really hit a handful of zombies at most, which isn't really balanced.

There's a big problem with balance with this approach. It makes it so that the only good way of utilizing weak and mid-strength concussives is cooking them and throwing them in the last moment. It also makes them only good for eliminating single strong targets rather than being the AoE option expected from grenades.

That's the idea with concussive explosives - 40mm concussive is not an anti-personnel weapon, after all. Currently, the difference between concussive and fragmentary explosives in Cataclysm is pretty minor. This is another part of what I'm trying to fix.

It's a fair bit more complex than just ignoring limb damage - fragments have accuracy which can boost or decrease damage dealt. I think the current formula is so that they can't headshot, but can good hit or normal hit. This could be simplified. That is, if there is a good reason to do so.

This can be rolled into f(p,d). Though if we do go through with upping the fragment count significantly, then we'll need to vastly streamline the current fragment-handling system for performance reasons. Unless I've greatly underestimated the efficiency of the ranged attack code, grinding out a few hundred of them will take a long time indeed. I've got a simple enough way to do this, though - we'd just need to examine shells generated by map::points_in_radius(center, radius, radiusz ) - map::points_in_radius(center, radius - 1, radiusz ) then identify what points to ignore as protected. Not quite as elegant a solution I'd say, but a more efficient one.

Unless I'm wrong about the efficiency of the ranged attack code. I hope I am, in fact.

More intuitive and "natural" (in the mathematical sense):

Er, I wouldn't say that - you're effectively doing the same exact thing using d = 1, power = neighbor_power, and 0.8 instead of 0.5. You also need to find the maximum neighbor power in that case, which further eats up time.

Also, it started out like that because at first I wanted to implement concussion being more useful in enclosed spaces. That was rather complex to calculate elegantly with unknown (as in - any possible) environment shape so I scrapped that part, but the formula stayed.

Yeah, that's a toughie. Maybe spawning a second, much weaker explosion when the shockwave hits a wall would work, but I'd be extremely leery of doing that for fear of causing massive cascades of phantom explosions. There's a very good reason few (if any) games actually simulate shockwave reflection.

Coolthulhu commented 8 years ago

if we switch to relying on fragmentation rather than concussion for most explosion damage

That would require coding a reliable fragmentation damage rather than the current wildly random one. Something that would not make glass windows stop the fragments, wouldn't have weird patterns that could be exploited for safety from the fragments and could be extended to 3D coords.

Which means that mines would benefit from falling off quickly.

Unlike vast majority of the explosives. And 0.4 factor makes them fall off quickly enough already.

Er, I wouldn't say that - you're effectively doing the same exact thing using d = 1, power = neighbor_power, and 0.8 instead of 0.5. You also need to find the maximum neighbor power in that case, which further eats up time.

Those are necessary parts of propagation algorithm and so are essentially free here. The formulation is more natural that way, though. The loss of power per tile traveled is easy to predict (except for the random factor that makes things more interesting). It's simpler conceptually, even if it doesn't simulate tile-less explosions too well.

And most importantly, it makes explosives useful for taking out more than one zombie at a time. Zombie movement is an important factor here - note how they almost never form a tight group.

At this point performance isn't a big concern. Even big explosions only take roughly as much time as a single NPC trying to find path from one end of the map to the other one.

Maybe spawning a second, much weaker explosion when the shockwave hits a wall would work

Sounds really hacky. A proper solution could utilize the fact that the algorithm is two-pass - first only terrain is damaged (to allow breaking weak obstacles, like windows), then everything else. A total volume vs. expected volume could be calculated, then damage could be scaled by that. But that wouldn't make a big difference without taking roofs and floors (or their absence) into account.

JoeKlesczewski commented 8 years ago

That would require coding a reliable fragmentation damage rather than the current wildly random one. Something that would not make glass windows stop the fragments, wouldn't have weird patterns that could be exploited for safety from the fragments and could be extended to 3D coords.

Do you find fault with the method I suggested? For reference:

Though if we do go through with upping the fragment count significantly, then we'll need to vastly streamline the current fragment-handling system for performance reasons. Unless I've greatly underestimated the efficiency of the ranged attack code, grinding out a few hundred of them will take a long time indeed. I've got a simple enough way to do this, though - we'd just need to examine shells generated by map::points_in_radius(center, radius, radiusz ) - map::points_in_radius(center, radius - 1, radiusz ) then identify what points to ignore as protected.

This lets us handle fragments abstractly rather than individually and therefore ensure consistency. It has its own problems, of course, but I don't think they are too bad all things considered.

Those are necessary parts of propagation algorithm and so are essentially free here. The formulation is more natural that way, though. The loss of power per tile traveled is easy to predict (except for the random factor that makes things more interesting). It's simpler conceptually, even if it doesn't simulate tile-less explosions too well.

I am going to have to disagree on this. A propagating explosion makes some sense, but it is neither as fast nor as natural (to my mind at least) as simply crunching a few numbers once per tile. No searching for neighbor_power needed.

And most importantly, it makes explosives useful for taking out more than one zombie at a time. Zombie movement is an important factor here - note how they almost never form a tight group.

They still would be. Part of my point is to fix how concussive grenades are also being used for this wide-area antipersonnel factor, which they are not good at all for. That's the role of fragmentary grenades. Do you disagree with this?

At this point performance isn't a big concern. Even big explosions only take roughly as much time as a single NPC trying to find path from one end of the map to the other one.

Grenade explosions already take a fairly long time, and I'm suggesting increasing the number of pieces of shrapnel by a factor of five or ten. It's possible I'm misunderstanding what's at play here, but it strikes me as a poor idea to try and use the same system with such a vast number of fragments.

Sounds really hacky. A proper solution could utilize the fact that the algorithm is two-pass - first only terrain is damaged (to allow breaking weak obstacles, like windows), then everything else. A total volume vs. expected volume could be calculated, then damage could be scaled by that. But that wouldn't make a big difference without taking roofs and floors (or their absence) into account.

It is very hacky, certainly. But I think for now it can be considered outside the scope of the issue.

Coolthulhu commented 8 years ago

I've got a simple enough way to do this, though - we'd just need to examine shells generated by map::points_in_radius(center, radius, radiusz ) - map::points_in_radius(center, radius - 1, radiusz ) then identify what points to ignore as protected.

Formulated like that, it sounds much too simple. I'm thinking more like shadowcasting level of complexity. Performance is of lesser concern here, until it becomes noticeably slow.

3D shadowcasting will be a part of 3D field of vision update, which is currently stalled due to me having no time to finish it. Current shrapnel code ignores the third dimension, so it doesn't need to wait for 3D shadowcasting, just needs to be formulated in a way that will allow easy migration to 3D.

A propagating explosion makes some sense, but it is neither as fast nor as natural (to my mind at least) as simply crunching a few numbers once per tile.

It's not propagation vs. some numbers. It's propagation vs. some unspecified method of calculating the area.

How else do you want to get the area covered by the explosion? Expanding spheres are out, because they would phase through walls, thus be unsuitable for 3D. It could be shadowcasting, but then shockwaves would have very sharp edges and act roughly the same way as shrapnel.

Part of my point is to fix how concussive grenades are also being used for this wide-area antipersonnel factor, which they are not good at all for.

They aren't good for taking out people who take cover. Against a horde of uncoordinated zombies with intelligence below that of an insect they shouldn't be totally useless.

Plus, it's not really realistic to make useful real life items be useless in the game just to make the numbers match newtonian mechanics.

Grenade explosions already take a fairly long time, and I'm suggesting increasing the number of pieces of shrapnel by a factor of five or ten. It's possible I'm misunderstanding what's at play here, but it strikes me as a poor idea to try and use the same system with such a vast number of fragments.

This was about the explosion expansion part rather than shrapnel.

JoeKlesczewski commented 8 years ago

Formulated like that, it sounds much too simple.

Thanks, I guess? Not sure what you mean by this.

I'm thinking more like shadowcasting level of complexity. Performance is of lesser concern here, until it becomes noticeably slow.

Got it. I'll leave in controls for later optimization, in that case.

It's not propagation vs. some numbers. It's propagation vs. some unspecified method of calculating the area.

How else do you want to get the area covered by the explosion? Expanding spheres are out, because they would phase through walls, thus be unsuitable for 3D. It could be shadowcasting, but then shockwaves would have very sharp edges and act roughly the same way as shrapnel.

Sorry - forgot to expand on this. You'd find a maximum relevant radius - call it m = sqrt(p) so that the concussive damage is one when d == m. Then, you'd operate on the output of map::points_in_radius(center, m, radiusz) to check for tiles that are not open to the center (and thus going to take the full force of the blast). This can be stored in a std::map<tripoint, double> cover. The double values would be the zero-to-one (inclusive) multiplier for the damage creatures and/or furniture on the tile experience. Then it is a simple matter on the next pass of the damage at a point pt distance d from the epicenter of an explosion with power p being cover[pt] * p / d ^ 2.

They aren't good for taking out people who take cover. Against a horde of uncoordinated zombies with intelligence below that of an insect they shouldn't be totally useless.

On open terrain? They'd still be terrible in real life for that sort of thing. Modern militaries pretty much don't use them at all for this reason.

But regardless, they'd not be useless at all ingame - since the concussive damage isn't stopped by intervening zombies, there's very good potential for dispatching clumps of them. I suggested above power levels of 200, 150, and 120. The first would pulp all low-level zombies in a 3x3 area and still do significant damage outside of that (though hulks can still survive several point-blank grenades). The second and third would pulp low-level zombies at the center, but leave them alive to varying degrees as you get further away. All of these are valid balance points, potentially - what I want to know is which one(s) you like and why.

Plus, it's not really realistic to make useful real life items be useless in the game just to make the numbers match newtonian mechanics.

Concussive hand grenades are not useful items in real life. Grenades are very uniformly fragmentary in modern times (i.e. after we discovered how much better fragmentary stuff is). If anything, we'll be severely powering these things up.

This was about the explosion expansion part rather than shrapnel.

Ah, I see.

Coolthulhu commented 8 years ago

Not sure what you mean by this.

I mean it sounds like it misses some important part.

Then it is a simple matter on the next pass of the damage at a point pt distance d from the epicenter of an explosion with power p being cover[pt] * p / d ^ 2.

And how do you pass the cover value further? I assume it doesn't reset to 1 back at every point, but takes the values from the last "ring" and integrates them somehow. The simplest way would be to check all the neighbors from the last "ring" (actually a sphere, just clipped to 2D) and pick the one with the highest damage. Another way would be to extend lines from center to current point and check the last one on the line, but that would lead to a lot of visible and predictable (exploitable) artifacts.

On open terrain?

On any terrain. Labs currently have concrete floors, meaning they can be treated as bunkers.

The first would pulp all low-level zombies in a 3x3 area and still do significant damage outside of that

200 / 9 = 22 - it's barely enough to be noticeable at distance 3. And 50 isn't enough to "count" against a hulk or a shocker brute, considering how much setup it involves. Meaning that the only way to really use it in a way that "counts" would be to cook the grenade till the last turn, then throw it at a hulk who is slowed down by terrain.

Unless we artificially widen the area, for example by counting the 3x3 in the center all as distance 1, but then we would be replacing a solution that does something with hacks that do the same thing, just with different formulas.

All of these are valid balance points, potentially - what I want to know is which one(s) you like and why.

I'm mostly concerned about the whole AoE thing. DDA has no good AoE, maybe with the exception of flamethrowers. Grenades kinda suck, but are rather expensive.

If the PR with the change somehow managed to fix that, I wouldn't care much for the concussion. If the shrapnel did the job, the concussion could be there just to wreck terrain and items, ignore armor, maybe cause statuses and generally just have a "support" role. But the shrapnel doesn't do all the job yet. It makes grenades more dangerous, but mostly against small numbers of targets.

JoeKlesczewski commented 8 years ago

And how do you pass the cover value further? I assume it doesn't reset to 1 back at every point, but takes the values from the last "ring" and integrates them somehow. The simplest way would be to check all the neighbors from the last "ring" (actually a sphere, just clipped to 2D) and pick the one with the highest damage. Another way would be to extend lines from center to current point and check the last one on the line, but that would lead to a lot of visible and predictable (exploitable) artifacts.

My thought was basically the first of your two ideas but instead of picking the highest cover modifier (and thereby rendering most cover useless) we'd instead perform a weighted average with greater weight given to the tile most directly between you and the explosion. Cover near the epicenter would therefore have a bit of a protective effect in further squares.

On any terrain. Labs currently have concrete floors, meaning they can be treated as bunkers.

By "open terrain" I mean terrain without obstacles to use for cover. The important point was that they're terrible in real life for AoE damage. Modern militaries pretty much don't use them at all for this reason.

200 / 9 = 22 - it's barely enough to be noticeable at distance 3. And 50 isn't enough to "count" against a hulk or a shocker brute, considering how much setup it involves. Meaning that the only way to really use it in a way that "counts" would be to cook the grenade till the last turn, then throw it at a hulk who is slowed down by terrain.

Unless we artificially widen the area, for example by counting the 3x3 in the center all as distance 1, but then we would be replacing a solution that does something with hacks that do the same thing, just with different formulas.

Then we can bump it up further, though at a balance cost. 320 power pulps almost all zombies in a 3x3 area, pulps all low-level zombies in a 5x5 area, and three of them next to a hulk will kill it. I think that's overkill - hand grenades really are a last resort in this kind of situation. I'm partial to 180 power, myself, since it pulps low-level zombies in a 3x3 area while two of them two tiles away from a zombie will kill it.

On the distance thing, I just realized I've been a bit inconsistent between d=1 at center (actually the case) and d=0 at center (which is of course nonsense) - that might be contributing some lack of clarity in my responses.

I'm mostly concerned about the whole AoE thing. DDA has no good AoE, maybe with the exception of flamethrowers. Grenades kinda suck, but are rather expensive.

If the PR with the change somehow managed to fix that, I wouldn't care much for the concussion. If the shrapnel did the job, the concussion could be there just to wreck terrain and items, ignore armor, maybe cause statuses and generally just have a "support" role. But the shrapnel doesn't do all the job yet. It makes grenades more dangerous, but mostly against small numbers of targets.

That's the idea. Boosting the efficacy of shrapnel against many targets is much of the idea. In fact, let me go set up a checklist of stuff to do over on the PR I made for this (#14036).

Coolthulhu commented 8 years ago

By "open terrain" I mean terrain without obstacles to use for cover.

And I'm talking about any terrain. If concussion sucks in the open, but is just as bad in enclosed spaces, we don't get much of that realism that this change is supposed to bring. There should be a situation where it doesn't suck.

Then we can bump it up further, though at a balance cost.

The effect of bumped numbers on the area is very minor compared to the effect on the epicenter. Meaning that the problem can easily get worse rather than better - the grenade now becomes a hulk-busting weapon that is too good against hulks to be used against weak stuff, while being too centered to be useful against loose hordes.

Concussion could be hacked to work better (lose less power per unit of distance) in enclosed spaces by checking for roofs. That could make it better at least for labs.

And a very important thing I forgot: bashing power is proportional to damage. There has to be multiplier on that or else 200 power grenade will destroy concrete walls and dig through solid rock.

JoeKlesczewski commented 8 years ago

If concussion sucks in the open, but is just as bad in enclosed spaces, we don't get much of that realism that this change is supposed to bring. There should be a situation where it doesn't suck.

If we want realism, concussion grenades should suck. They're only ever used against divers and frogmen as far as I understand. And 40mm launched concussive grenades were designed for anti-emplacement roles, not antipersonnel ones.

The effect of bumped numbers on the area is very minor compared to the effect on the epicenter. Meaning that the problem can easily get worse rather than better - the grenade now becomes a hulk-busting weapon that is too good against hulks to be used against weak stuff, while being too centered to be useful against loose hordes.

This is why I am partial to 180 epicenter damage. That still pulps low-level zombies in the center 3x3 while damaging them for over half their life in the outer 5x5 (some damage in the outer 7x7, of course) and needing three direct hits to kill a hulk. Is that not sufficient AoE damage?

Concussion could be hacked to work better (lose less power per unit of distance) in enclosed spaces by checking for roofs. That could make it better at least for labs.

Powering it up based on ceilings is a very good idea, actually. Is it possible to make soundless explosions? We could just call explosion a second time, in that case.

And a very important thing I forgot: bashing power is proportional to damage. There has to be multiplier on that or else 200 power grenade will destroy concrete walls and dig through solid rock.

Ah, that's good to know. Any idea where/how this is handled?

kevingranade commented 8 years ago

The reason fragmentation processing takes so long is because it has an animation delay built into it from using the shoot() code, if you simply removed that you'd probably be fine with any non-insane solution.

For example, if we assume targets are relatively sparse, you can do an expanding circle/sphere to track the power level of the explosion, then each time you encounter a target you can draw a line to the target, noting obstacles and adjusting or negating the effect on the target. It's going to end up drawing the same line multiple times, but it'd probably be fast enough for the smallish radius explosions have.

We also happen to have a single-pass FoV algorithm that can have actors plugged into it, that might do the job pretty well, which might be extra good if we want to try to do something like reflecting blasts.

My understanding of the state of the art WRT concussive vs fragmentation grenades is that there's simply no tradeoff to be made, because making a concussive grenade also act fragmentary doesn't reduce the concussive force, so it's not the case that the concussion is ineffective, it's just that fragmentary grenades are the best of both worlds. My understanding matches Coolthulu's, which is that concussive blasts are massively lethal in enclosed spaces.

I'd much prefer a solution where shrapnel is treated as a field rather than individually modelled though, the whole point is that there are nearly uncountable fragments, which makes it intrinsically a poor match for discrete modelling.

JoeKlesczewski commented 8 years ago

For example, if we assume targets are relatively sparse, you can do an expanding circle/sphere to track the power level of the explosion, then each time you encounter a target you can draw a line to the target, noting obstacles and adjusting or negating the effect on the target. It's going to end up drawing the same line multiple times, but it'd probably be fast enough for the smallish radius explosions have.

For a concussive blast this will not work, unfortunately - the way shockwaves refract around corners means that only considering the obstacles on the line to the epicenter would be unduly exploitable.

This is the algorithm I'm using for the fragmentation stuff, though.

We also happen to have a single-pass FoV algorithm that can have actors plugged into it, that might do the job pretty well, which might be extra good if we want to try to do something like reflecting blasts.

That sounds very interesting - could you direct me towards where that would be?

My understanding of the state of the art WRT concussive vs fragmentation grenades is that there's simply no tradeoff to be made, because making a concussive grenade also act fragmentary doesn't reduce the concussive force, so it's not the case that the concussion is ineffective, it's just that fragmentary grenades are the best of both worlds.

Yeah, that's what it boils down to - fragmentary grenades are far more lethal than concussive grenades, simply due to the fact that they need so much less explosive material to achieve the same effect. There's only so much TNT you can pack into a grenade before it becomes impracticably heavy, after all.

My understanding matches Coolthulu's, which is that concussive blasts are massively lethal in enclosed spaces.

According to this US Army manual, concussion grenades are "less lethal than fragmentation grenades in open areas but are effective within enclosed spaces". This doesn't strike me as meaning "massively lethal", especially because as far as I can tell concussion grenades are no longer standard-issue to US forces even in urban operations.

Either way, I was planning on using Coolthulu's idea of powering up concussive damage while under a roof as a bit of a stopgap until we implement blast wave reflection.

I'd much prefer a solution where shrapnel is treated as a field rather than individually modelled though, the whole point is that there are nearly uncountable fragments, which makes it intrinsically a poor match for discrete modelling.

Depending on what you mean by "field" that's what I intend to do - for each point that we need to find the damage at we can start at the epicenter and traverse the path to the point, accounting for falloff and obstacles.

Where I do need some help is the scaling. For instance, if I want a blast/fragment/whatever to do 100 damage to a zombie, what number do I need to send to the damage-dealing code? That sort of thing is very difficult to learn just by poking around in the code.

Coolthulhu commented 8 years ago

If we want realism, concussion grenades should suck.

In that case it would be a good idea to at least give current concussive bombs some other effects. Say, add extra nails/scrap to cost and add fragments. Maybe not in the same PR, but still.

Useless items that pretend to be useful are a noob trap.

That sounds very interesting - could you direct me towards where that would be?

Check out lightmap.cpp, castLight function and its usage in build_seen_cache.

Depending on what you mean by "field" that's what I intend to do - for each point that we need to find the damage at we can start at the epicenter and traverse the path to the point, accounting for falloff and obstacles.

Keep in mind that there can be weak obstacles along the way (and next to it). It wouldn't look OK if glass window stopped grenade shrapnel.

Where I do need some help is the scaling. For instance, if I want a blast/fragment/whatever to do 100 damage to a zombie, what number do I need to send to the damage-dealing code?

Depends on how do you want to achieve that.

You could deal damage directly which would be simple, but that would be rather unrealistic with regards to armor and wouldn't trigger special effects.

You could trigger attack multiple times based on "shrapnel density". This would respect armor more properly, but still wouldn't trigger effects.

The best way to do it I can think of would be to check how much "shrapnel density" is on creature's tile, roll a number of shrapnel pieces based on that and then make fake ranged attacks using those pieces. This is already done against the targets in the epicenter, in the shrapnel code. Except for the shrapnel density of course. This solution would have the advantage of not requiring you to roll for body parts, check for armor, apply the effects yourself, check for monster defense etc.

As for bashing: it is in do_blast code. Search for m.bash there.

kevingranade commented 8 years ago

Personally I'd like to have a test-based lethality, basically import the lethality guidelines from the weapons manuals into integration tests, and run a few simulations to determine if it roughly matches. This requires a few assumptions about distance and such, but we can at least document them and the expected behavior.

mugling commented 8 years ago

Obsolete following recent PR's concerning this subject

JoeKlesczewski commented 8 years ago

I never finished this? My apologies, I could have sworn I did.

Moot now, though.

mugling commented 8 years ago

14036 remains open. The shrapnel implementation was replaced in #15621 although the shockwave part still needs completing