Line of sight and cover rules

Line of sight and cover behaviour seems downright backwards - turrets, in particular (that’s the main enemy that fires at you). I can’t see the turret because I’m face-first against a wall, but hey, it can quite happily shoot me to death.

Um, no. That’s backwards. I’m hugging a concrete wall that it can’t shoot through - I have nice, hard, impenetrable cover, especially if I can’t even bloody see it.

When the turret is lined up with the door, there is NO safe way to open that door. The “peek” mechanic seemed to cover things nicely in the last stable, but (probably as another side effect of the bloody lighting rework), now it’s usually useless, as well.

The only way to know about turrets without exposing yourself to fire is to make use of the lighting bug that already existed and isn’t fixed by the lighting rework…

Is there anything in the works on this? It’s really bloody stupid.

The problem here is that there are some very rare edge cases where the “draw a line” code trips ever so slightly and the line it draws from tile A to tile B doesn’t quite match up exactly (this is usually because of times where it hits two different tiles that would both be valid for the line due to the line trying to pass right on the border between the two). In very rare cases this will let things see around corners without you being able to see them back, and it’s definitely not an intended effect (just something that is in a very sensitive and speed important bit of code, and it’s rare enough that for now we’re mostly leaving it alone rather then sacrifice major speed improvements in an attempt to fix it).

Peek was working fine last time I checked it (assuming a closed door, to eliminate possible procs of the aforementioned bug), though I guess it’s hypothetically possible something has changed. Nobody’s touched any code involving it recently that I know of though, so it should still be functioning exactly the same as before.

And can you elaborate on “the lighting bug that already existed and isn’t fixed”? It’s totally possible you are seeing something that’s intended and thus not a bug, or that we just don’t know about because nobody has bothered to report it.

You can open doors from a diagonal, and then peek. This lab guide here might help you:

https://dl.dropboxusercontent.com/u/8970937/CDDA/labguide.jpg

[quote=“Chezzo, post:3, topic:10181”]You can open doors from a diagonal, and then peek. This lab guide here might help you:

https://dl.dropboxusercontent.com/u/8970937/CDDA/labguide.jpg[/quote]

I’m speaking specifically of opening a door from the diagonal and peeking. “peeking” is an action, and it takes a turn. When you’re done peeking, currently, it’s common for the turret to shoot you in your happy little diagonal spot. That is specifically what I’m complaining about.

The peeking does work fine, I didn’t mean to say that it isn’t working as intended… it’s that, since you are “peeking” from an unsafe tile, you still get shot, so it doesn’t keep you safe, so it doesn’t “work” when it comes to checking for turrets.

And it’s not rare. It’s so common that I just don’t even open the doors with turrets behind them anymore (which I know, because of the bug), or I open them from straight on so I can see the turret without peeking, depending on the usual one turn wait before it shoots (but it doesn’t always…). As best I can tell, if the turret is lined up with the door, it can shoot both diagonals from the door FAR more often than not.

The bug I am referring to is walls being lit up for your vision from the other side of the wall - that is, I can tell there’s a light source (usually a turret when in a lab) from the other side of the solid concrete wall because the wall is considered “lit”. That’s a bug, yes? Please tell me that’s not intended…

Why not just peek with the door still closed? Last I knew that worked just fine (or at least it should, I certainly remember a PR about it at some point and it’s not something that I’m opposed to).

No that’s not intended. :stuck_out_tongue: And you’re still getting it in the latest experimental? There have been a lot of vision tweaks even in just the last month or so.

[quote=“i2amroy, post:5, topic:10181”]Why not just peek with the door still closed? Last I knew that worked just fine (or at least it should, I certainly remember a PR about it at some point and it’s not something that I’m opposed to).

No that’s not intended. :stuck_out_tongue: And you’re still getting it in the latest experimental? There have been a lot of vision tweaks even in just the last month or so.[/quote]

OK, noob moment… you can peek through a door? Well, that would certainly help a LOT! Durrr…

But yes, I was getting it on the one I downloaded just a few days ago, 3458. Or maybe 3438, I’ve got that one lying around, too, and I don’t remember which one I had up at the time. Either way, quite recent.

Edit: OK, no, you can’t peek through doors, at least not the ones in labs. I do seem to remember peeking through some house front some time ago - perhaps the door has to have a peephole? That would make sense… Anyway, no, it doesn’t work in labs.

Oh, and I tried the latest build (3481) - bug still very much present. I do have nightvision, that could be making a difference.

Only specific doors let you peek through them, doors with windows or peepholes.

That would be a reasonable feature though, peek through a door by opening it a crack and looking, with some chance of being noticed, or even adding an endoscope to look under doors undetectably.

That’s a side issue compared to the other one, which is basically that fully symmetric LoS is a pain in the ass to code.
There’s some basic reading material here: http://www.roguebasin.com/index.php?title=FOV
DDA uses an extension to the shadowcasting algorithm I came up with to handle partial occlusion of tiles, i.e. smoke effects, and dynamic lighting.

There might be some adjustments we can make to get fully symmetric LoS in DDA, but I don’t think it’s going to be quick or easy.

We could have players use map::sees in addition to cache. This would be a bit more expensive and would result in seeing monsters on otherwise unseen tiles, but could solve most of the turret problems.

We might actually need to do this in 3D FoV update. I don’t think 3D shadowcasting on the entire visible area would run in acceptable time, so we’ll need to look for creatures separately.

I’m actually familiar with the math underlying LoS calculations, and I don’t think that’s really the problem. I’m mean, sure, symmetric might be nice (then again, maybe not), but currently, I can fire at things (at least with throwing… hmmm) that I can see, but my attack is blocked by terrain in between.

That is what should be happening here. Sure, maybe it can see me and I can’t see it - that’s a relatively minor problem (solved by peeking). The problem is that it can SHOOT me there.

..T.. ..... ..... ..... ..... WWDWW .M.M..

So, if that’s Me standing in either of the M spots, and that’s the Turret at T, I have to peek to see it (which is fine), but it can shoot me (which is not). In a reverse situation (again, at least with throwing), if I target a zombie there, I hit the wall.

I’m fine with being able to see things that have hard cover - it’s actually a good idea. But when you’re shooting at something, if you don’t have LOS to the center of the square (or at least 2 or 3 corners, if that’s an easier calculation), then either you should be hitting the cover, or the shot should be much more difficult, with most misses hitting the cover.

It’s because shooting has to be able to “force” a specific choice of path when drawing the shot line, to account for seeing things in a small gap between two larger objects. That makes the algorithm run something like this:

  1. Player is unable to see the robot, due to tracing from their point of view.
  2. Robot is sometimes able to see the player, depending on random factors involved in the particular path choices made during it’s sight tracing.
  3. If the Robot sees the player, then it is able to “force” the bullet to follow the particular path that resulted in it seeing you.

It’s a side effect of the way an angled line translates to a grid pattern. To use your example above, let’s say the turret shoots a bullet at precisely 9.46 degrees west of south. Translating this into grid co-ordinates, that means that for every 6 tiles down (south) that the bullet flies, it will drift over exactly one tile. Handling this seems simple, just count how many tiles you’ve gone down, and for every 6th one move left (west) 1 tile as well as moving down one tile. Yet draw this line on your diagram, and we notice something interesting.

..T.. ..1.. ..2.. ..3.. ..4.. WW5WW .6....
And there you have the basics of what’s happening, and there isn’t necessarily any good way to fix it without creating edge cases in the other direction, where you should be able to shoot something but you can’t. Additionally I’d like to point out that this can also hypothetically happen in favor of the player; should a turret be standing near a wall and the player some distance away, it’s completely possible that the player could be able to shoot the turret and it would be unable to return fire despite you being in range. However for this to work (unlike the targeting example) the player has to be able to force the exact same path rolls as the turret would, which means a similar recoil value and a similar skill one. Get the exact same rolls, and your shot will “curve” around the corner just as the turret’s would.

I came back to the boards to say that I just used it on a turret, actually - I found a TOOLBOX in a utility room in the lab, used it to make a bookshelf, pushed the bookshelf up to the turret, the backed off and moved over one square… and threw spikes at the turret until it died.

Well, there will ALWAYS be “edge cases”, because there will always be edges, but that doesn’t mean there aren’t good improvements, even if they literally don’t “fix” every single situation. In this case, the “go 6 and bump over one” algorithm can be massively improved by simple offsetting by half the first time - that is, if it’s 1/6, only go 3 the first time, then go 6 every time after that. If you actually draw a straight line, center of square to center of square, that’s what you get.

Going 6, then bumping over one is lazy, essentially truncating remainders until you a whole instead of rounding when you should. This has the happy side effect, if you apply this to line of sight as well, of having FAR fewer cases where A can see B but not the other way around.

And, assuming one didn’t want to do that, bumping over 1 FIRST, then going 6 would give a much more life-like situation, where the one in cover can shoot the one standing out in the open, but not the other way around. Currently, we have the reverse of that, which is silly.

AFAIK this won’t change anything. Shadowcasting and bresenham line drawing should make the same decisions about visibility of tiles. The problem is bresenham isn’t reversible either, as i2amroy illustrated. I can tack this onto the shadowcasting unit test to verify though.
What I was thinking was going the other way, don’t let monsters see the player if the player doesn’t have LoS to the monster.
This is a little problematic due to things like mirrors and cameras augmenting player FoV, but in almost all cases the monster would also be drawing a line to the player to check and failing.

AFAIK this would be totally reasonable, the reason shadowcasting is a must for player vision isn’t detecting monsters, it’s because we need to map out the visible region in it’s entirety in order to draw the map. If the view of not-current-z-level tiles is implemented in such a way that we can just shadowcast to potentially drawn tiles, we can handle all the rest with visibility spot-checks. I’d still prefer to shadowcast everywhere, with optimizations like changing resolution for empty sky tiles, but if that kind of thing doesn’t pan out spot checks might be workable.

In this case, the “go 6 and bump over one” algorithm can be massively improved by simple offsetting by half the first time - that is, if it’s 1/6, only go 3 the first time, then go 6 every time after that. If you actually draw a straight line, center of square to center of square, that’s what you get.

Going 6, then bumping over one is lazy, essentially truncating remainders until you a whole instead of rounding when you should. This has the happy side effect, if you apply this to line of sight as well, of having FAR fewer cases where A can see B but not the other way around.

And, assuming one didn’t want to do that, bumping over 1 FIRST, then going 6 would give a much more life-like situation, where the one in cover can shoot the one standing out in the open, but not the other way around. Currently, we have the reverse of that, which is silly.[/quote]
No, we don’t. i2amroy was illustrating the problem, but the actual implementation does start “mid-iteration” instead of at the “start”. If you’re curious take a look at line.cpp.
One exception to this default is that map::sees() and line_to() conspire to put “spin” on the starting value for the trajectory to emulate “visible from any point on the initial square” as i2amroy points out. Originally this was only used by the player, but at some point the code handling it got unified and now it’s fair :slight_smile:

No, we don’t. i2amroy was illustrating the problem, but the actual implementation does start “mid-iteration” instead of at the “start”. If you’re curious take a look at line.cpp.[/quote]

I’m not talking about what the code says, I’m talking about actual game play, and yes, that’s exactly what we have right now: the guy behind cover can’t shoot at the guy standing out in the open, but the guy standing out in the open can shoot at the guy behind cover. I’ve given examples of it in this thread, and you can try it yourself in less than 5 minutes in any lab start.

Whatever is going on under the covers, that’s the result, and it’s silly.

Also, in terms of starting in the middle of an iteration, that would look like this:

..T.. ..x.. ..x.. ..x.. .x... .x... .x...
but what actually happens in the game is this:

..T.. ..x.. ..x.. ..x.. ..x.. ..x.. .x...

That’s why having cover doesn’t work (unless it’s complete cover), so again, I don’t doubt what you say is going on under the covers (I’m certainly in no position to do so, and thank you for your hard work on this game I enjoy!), I’m talking about the end result.

Well…I can think of a few ways of solving it.
First is calling the line calculation in both directions, then allowing or disallowing those edge cases. Disallowing if one of the two checks fail might be more beneficial as it then wouldn’t matter which one is used for firing calculations. But that may be unacceptable to double the amount of calculations.

Second is to reverse the line calculation. The other edge case will come up of shooting from corners. This could be solved if an entity does something other then wait, have other entities allow to make the line calculations both ways on that tile only. This would unfortunately cause some issues with shooting, unless the firing/shooting code is also changed a bit to allow for two calculation paths to the target then picking the path that reaches.

Third is implementing a different fov calculation system. But that is no trivial thing.

What about making all line calculations use the same order?

For example, have all calculations start in the more upper-left point of the two and end in the more lower-right one.

In case where this is ambiguous (we go from upper-right to lower-left), the “upper-leftness” would be determined first by the coord with larger difference. For equal difference, we’d just hardcode x or y as the privileged coord.

That way we’d have an unambiguous, deterministic way to guarantee symmetry of “x sees y” relation, without significant processing overhead.

Not sure how would that look, though.

Mid iteration doesn’t exactly fix all of the problems either. All it means is that the “broken” angle now becomes half that of what it was previously. Shooting at a 4.73 degree angle with a mid-path drift will let a bullet “curve” around the wall exactly the same as a 9.46 degree angle with an end-path drift will (since 12/2 = 6/1).

That could work, and would certainly be a viable strategy, though as you mentioned we’d probably need to run some “what does it look like” tests first.

Mid iteration doesn’t exactly fix all of the problems either. All it means is that the “broken” angle now becomes half that of what it was previously. Shooting at a 4.73 degree angle with a mid-path drift will let a bullet “curve” around the wall exactly the same as a 9.46 degree angle with an end-path drift will (since 12/2 = 6/1).[/quote]

I never claimed it would - in fact, I said that there would always be “edge” cases. The point is to make the broken stuff rare and/or not painfully obvious to the player, and the current situation is very common and very obvious.

But to the specific point you brought up, if you use mid-iteration, there are no painfully obvious bends. There are still edge cases, where one square this way or that way makes it possible, but right here isn’t (or vice versa) and it isn’t just QUITE right, but that is inherent a square-based system.

Any time it’s just off 90 or 45 degrees, it will be more visible to the human eye, there’s no getting around that, and it’s most obvious at short ranges, there’s no getting around that, either, but when having the one extra movement (just off straight or just off 45) be in the middle of the line instead of either end looks and behaves best. Having it at one end or the other ends up looking “hooked” to the human eye AND allows for highly exploit-ly behaviour (like pushing a bookshelf up in the turret’s face, then backing one and offsetting one square to kill it easy).