Cataclysm-dda: Angled vehicles develop holes [$15]

Created on 23 Jan 2014  路  25Comments  路  Source: CleverRaven/Cataclysm-DDA

While all this vehicle renaissance is going on, does it seem feasable to tackle that problem where cars at a 45-degree angle can be entered diagonally between otherwise solid parts? I think you know what I mean, how if two boards are adjacent vertically, at an angle you'll cross between them somehow. Ideally it would check the vehicle structure and make the space beyond functionally impassable/opaque from only that side. It'd probably be a tough fix, but it ought to happen at some point.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

<Enhancement / Feature> <Suggestion / Discussion> Bounty Vehicles

Most helpful comment

@mlangsdorf Sorry, I guess I botched typing that. The idea is that instead of having a single boolean representing whether a tile is traversable, to have a field of 8 bits representing directional passability. For ordinary terrain, it would always be either 0 or 255, but for rotated vehicles... actually, it's a bit of a PITA, but I'll draw a demonstration of sorts.

Demonstration

With red/orange dots representing bits that are 1. If they're all 0 or 1, code can just treat them exactly as it currently does, alternatively it takes a slower path which checks the individual appropriate bit.

E.g. still check obstacles, but situationally(vehicles), do a directional check instead since a boolean is insufficient to represent the fact that only some tile boundaries are impassable.

All 25 comments

Probably would require a bit of an update with pathing where squares could be flagged as "diagonally impassable", which would mean if two diagonally impassable squares are diagonal to each other you can't cross between them diagonally.

So long as it only applies to vehicles, I'd imagine.

Any chance of getting a fix?

This issue was opened seven months ago and never resolved.
What do you think?

Spewing bile is more likely to slow dev work, since I don't think we code with 3-4 environmental resistance on our eyes. Don't be a boomer!

I'm sorry, I didn't know stating plain facts was a hate crime. My deepest apologies.

It'll probably be folded in with a bigger vehicle update once that sort of thing rolls around. I think dev is mostly on some other polish right now, and I think the z-level bounties which are a tough target. But let's just hold out for the moment; even when I put it up it was just to put down the issue for being logged.

Many years later and I have a proposal to fix it, but no time to implement it at the moment.

Any time a vehicle is skewed, add a "clone" of the shifted part that covers the gap.

Tiny ascii illustration:
Facing north:

####
|00|
|00|
####

Rotated to NE:

####
 \00\
  \00\
   ####

Rotated to NE, plus gap covers:

#####
\\00\\
 \\00\\
  #####

To make it even simpler, widen the vehicle in the two locations that this scheme avoids, it doesn't prevent problems, but it makes it consistent:

######
 \\00\\
  \\00\\
   ######

Additionally, when a vehicle is "partially skewed", you can either just block the gaps:

####
\00\\
\\00\
 ####

Or widen the whole vehicle:

######
\\00\\
 \\00\\
 ######

This effectively makes the vehicle slightly thicker when skewed, which might cause some unexpected collisions, but that's a lot easier to cope with than the existing gaps.

The tricky part is taking collisions to the "cloned" parts and allocating the impact correctly to the original part.

Many years later and I have a proposal to fix it, but no time to implement it at the moment.

Any time a vehicle is skewed, add a "clone" of the shifted part that covers the gap.

Tiny ascii illustration:
Facing north:

####
|00|
|00|
####

Rotated to NE:

####
 \00\
  \00\
   ####

Rotated to NE, plus gap covers:

#####
\\00\\
 \\00\\
  #####

To make it even simpler, widen the vehicle in the two locations that this scheme avoids, it doesn't prevent problems, but it makes it consistent:

######
 \\00\\
  \\00\\
   ######

Additionally, when a vehicle is "partially skewed", you can either just block the gaps:

####
\00\\
\\00\
 ####

Or widen the whole vehicle:

######
\\00\\
 \\00\\
 ######

This effectively makes the vehicle slightly thicker when skewed, which might cause some unexpected collisions, but that's a lot easier to cope with than the existing gaps.

The tricky part is taking collisions to the "cloned" parts and allocating the impact correctly to the original part.

A better solution would be to make it so that the gap covers count as one part, even though they appear as two when the vehicle is at an angle, meaning...
(X = Part being damaged)

######
 X\00\\
  \\00\\
   ######

Instead of just basically doubling the amount of parts when the vehicle is at an angle...

######
 XX00\\
  \\00\\
   ######

They are counted as one part. So it appears that two parts are being damaged, even though it's really one part being damaged, and it would show up like that once the vehicle straightens out.

I hope I didn't make this too complicated. But I also hope this issue doesn't become five years old, lol

Alternative idea: An 8-direction bitfield on every tile, which remains zeroed for terrain, but for vehicles and their neighboring tiles is computed based on the traversability of the original, unrotated vehicle. If the appropriate bit is 0, any checks proceed as they usually would, but if it's 1, a more involved check can be performed to see what other tile the current algorithm(raycasting, movement, pathfinding) should be redirected to. It'd also work for non-boundary walls as well.

I'm probably ignorant about how the current code looks, but my intuition says algorithms could probably be changed to use this bitfield, possibly replacing bool->bitfield for visibility also, thus leaving the standard checks(==0 and ==255) intact, e.g. without injury to performance for the common cases.

Would probably be a pretty involved change, though it could conceivably be futureproofed against if someone wants to do portals some distant baleful day. One way or the other.

I honestly have no idea what that bitfield is supposed to do or how it's supposed to work. Can you explain with a concrete example?

For instance:
There is a standard car at local position [ 3, 3 ]. It has a windshield at mount [ 1, 2 ], a door at mount [ 1, 1 ], and a door at mount [ 1, 0 ]. It's pivot point is actually mount [ 0, 0 ], it's turned 45 degrees, and the parts have local position [ 2, 5 ], [ 3, 4 ], [ 4, 3 ], starting at the windshield and then the two doors. An NPC is near to the car at [ 5, 5 ] and wants to get in to steal my katana, sitting on the seat at [ 3, 3 ].

Currently, the NPC movement code checks to see that there are no obstacles between [ 5, 5 ] and [ 3, 3 ]. There aren't, so the NPC walks to [ 4, 4 ] and then [ 3, 3 ] and can take it.

How are the bitfields changing this situation?

@mlangsdorf Sorry, I guess I botched typing that. The idea is that instead of having a single boolean representing whether a tile is traversable, to have a field of 8 bits representing directional passability. For ordinary terrain, it would always be either 0 or 255, but for rotated vehicles... actually, it's a bit of a PITA, but I'll draw a demonstration of sorts.

Demonstration

With red/orange dots representing bits that are 1. If they're all 0 or 1, code can just treat them exactly as it currently does, alternatively it takes a slower path which checks the individual appropriate bit.

E.g. still check obstacles, but situationally(vehicles), do a directional check instead since a boolean is insufficient to represent the fact that only some tile boundaries are impassable.

Just to clarify, red dot means it's impassable? So most parts are impassable from all directions, and possible holes (orange) are impassable on diagonals?

@Zireael07 Correct. This could hypothetically be used to avoid holes within the vehicle, as well as making diagonal passages impassable, or directionally passable tiles(turnstile).

Thanks, I think that's a lot clearer.

So the seat tile at mount [ 0, 0 ] has its bitfield set so that diagnol movement is impossible. NPC pathfinding algorithm sees that's impossible to move from [ 4, 4 ] to [ 3, 3 ] and proceeds to bash the windshield.

Fair enough.

I'll defer to Kevin as how hard it would be to get this to interact with the light, vision, and pathfinding code.

The impact to the code would be VERY high, not only would everything that cares about opacity, damage application, navigation or movement have to be updated, but it changes the current "can I enter this square/can I see through this square" check to "can I enter square x from square y/can I see into square x from square y".
I'm not at all sure how this would interact with vision. The way vision interacts with opaque tiles is that you can see the opaque tile, but nothing past it. In this case is it the tile adjacent to the vehicle that counts as opaque or the vehicle tile itself?

From the point of view of addressing the diagonal gap issue, I much prefer the other solution, it's completely localized to the vehicle system instead of requiring updates throughout the rest of the code.

Yeah, it'd probably touch a lot of code. And you'd probably have to do two branches instead of one, one to cover ==0 and one for ==255, before finally falling back to the directional code. And in this case, the tile which cannot be entered from the current direction would be considered opaque. E.g. from inside the vehicle, the grass tile is opaque, from outside, it's the inside one that is.

Still, I wanted to pitch the idea mainly, since idk, creating faux parts strikes me as really inelegant. It does sound efficient and effective, but... well, there's a reason why I have difficulty managing coding nowadays.

Asmageddon's solution sounds ideal to me, but the impact issue is important too. The bitfield can't be applied only to vehicle tiles?

It's not whether it can be applied only to vehicle tiles or not, it's the other areas of the code that need to know about the bitfield.

The nice thing about Kevin's hack is that it isolates all the changes to the vehicle code.

I've been having a look at this issue, and I have the impression the duplicate part approach won't be entirely localized to the vehicle code. Suppose one of the walls is a closed door and it gets duplicated to cover a gap. If the player opens the door, we'd have the option of either removing the duplicate (which I think would look glitchy) or keeping it. If it's kept, what happens when the player (or something else) moves on top of the open door? Does the character exist on both tiles at once? I guess not, since that would look weird and probably have further undesirable consequences.

So suppose a player can be on top of one vehicle part, while not being on top of its duplicate or vice versa. What happens when you try to close the door, either through the tile you're on or the one you aren't on? The door closing code in src/gates.cpp would need to be aware that if you try to close a door on a given tile, there might be a creature on another duplicated tile that would prevent that door from closing. Would it be acceptable for the hole plugging logic to leak into other code like that?

You could argue that instead of duplicating doors, another neighboring unpassable wall tile could be duplicated, but that would be brittle since it wouldn't work if somebody decides to put multiple doors next to each other in the wall. I suspect that would also give glitchy looking results.

You talk about "looking", but why shouldn't the phantom parts just be invisible view- and navigation- blockers?

If the duplicates are invisible but behave the same as their parent when it comes to damage / collisions / interaction / etc, wouldn't that be confusing to the player?

And if the invisible parts don't behave like one of the real ones and only block viewing and navigation, then I suspect we're back in the scenario where movement and line of sight code need to be updated to take that into account.

Suppose you have a little scene like this:

.\Z
@I\

@ being the player standing outside, Z a zombie inside a vehicle, \ a vehicle wall, . some empty terrain and I an invisible view and navigation blocking tile that looks like the terrain below it.

The zombie won't be able to see the player and vice versa. But the player also wouldn't see the bottom wall tile unless the line of sight code treats the invisible tile differently.

I assume there's a final tilemap of values like is_collidable, is_opaque, etc.

It's a bit of a disgusting hack, but in theory it'd work perfectly and be reasonably efficient to group FOV-capable creatures/objects/vehicle parts by which vehicle they're in(if any), and toggling seam-boundary opacity flags.

E.g. player and NPC are inside vehicle, for their group the tiles just outside the vehicle are set to OPAQUE(or something like OPAQUE_DONT_RENDER, so it shows up as black), next is group outside of vehicles, for them seam tiles just inside the vehicles are set to same, and so on and so forth, with tile flags being restored between passes.

This data is going to be in cache anyway, won't require changes to FOV code, phantom parts, etc. It will require a check before casting FoV/LoS, but as long as you sort entities by which vehicle they're in, it should either yield to branch prediction or for it to be possible to do away with the check in those cases.

This issue has been mentioned on Cataclysm: Dark Days Ahead. There might be relevant details there:

https://discourse.cataclysmdda.org/t/avoiding-being-grabbed-out-of-vehicle/22455/3

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RogueYun picture RogueYun  路  3Comments

tinukedaya picture tinukedaya  路  3Comments

BorkBorkGoesTheCode picture BorkBorkGoesTheCode  路  3Comments

ituluwituluwzev picture ituluwituluwzev  路  3Comments

jeremyshannon picture jeremyshannon  路  3Comments