Diagonal vehicle fix

Rather than ray casting, why not just cache a short list of interior and edge tiles for the vehicle (ignoring inside/outside, just looking at location)? That’s like 2 extra bits per vehicle tile, so it’s not exactly a lot of data you are adding, and then the attack logic looks like this:

if (attacker is on vehicle) { if (attacker is in "interior") { atk_loc = 1; // on the vehicle "interior" } else { atk_loc = 0; // on the vehicle "edge" } } else { atk_loc = -1; // not on the vehicle } if (target is on vehicle) { if (target is in "interior") { targ_loc = 1; // vehicle "interior" } else { targ_loc = 0; // vehicle "edge" } } else { targ_loc = -1; // vehicle "exterior" } if (abs(atk_loc - targ_loc) <= 1) { // i.e. their "zone" and adjacent zones, but not 2 zones over, "interior" -> "edge", but not "interior" -> "exterior" attack(); } else { can't_attack(); }
That’s going to be even faster than raycasting, since you are just doing basic boolean checks, though it would require a little bit of extra time to build the cache during construction or total destruction of parts of the vehicle. Since that’s fairly rare compared to the amount of monster attack checks I feel like it would probably work more efficiently in the long run, though.

So we only really need to translate the attacker's position to the same coordinate system as vehicle pointing north would have.
It's like having that virtual, free map-space I mentioned. Anyway it's good. Still you'll need to transpose the position but that shouldn't be something hard. IIRC there is already worldcoord-2-localcoord function in vehicle.c. I should probably check the source code.

I don’t understand the raycast system, though. What’s the point? Why don’t just rotate the moving/attack vector by the corresponding value?

  1. Vehicle rotation direction and angle
  2. Zombie rotation around the center direction and angle
  3. North direction (cardinal direction)
  4. Current vehicle direction
  5. Current zombie positition
  6. Zombie position after rotating
  7. The center of the vehicle
  8. Original direction
  9. New direction

You just turn the vector. Of course it should rounded to either side.

Of course that function is to be activate every time zombies go/attack vehicles.

I believe it should be also be applied for bullets, thrown objects, explosions. This is what will make coders suffer with intergrating that system. Perhaps there should be simpler solution. Not only are simpler solutions easier to implement, it’s also may be easier to intergrate making the code even more modular.

UPD: coord_translate it is. It should be in reverse in our case, though, since it converts local coords into global ones. Also it’s used only once which is not good.

I would like to note that I was very recently grabbed and dragged out through my survivor-APC while I was driving it by a Grappler zombie. (Thank you Kevin, for putting in a debug menu to negate stupid bullshit like this when it happens)
Things like this and being hit by acid-bolts from corrosive/spitter zombies as well as gunshots from turrets/chickenwalkers while inside fully armored tanks means that this is still a considerable problem for all avid vehicle-goers, which I assume is everyone.

And what would you do with the rotated vector?
We still need an alternate target for the zombie, so that it doesn’t just stand still, trying to attack a player behind “diagonal vehicle forcefield”.
There could be some different solution, but casting a ray and considering attacking the second and third tile of it would be a relatively simple solution.

Just interior/edge/exterior wouldn’t be enough. Consider the case:

| | |
| @ |
z | .

'z’ombie is standing on a non-vehicle tile.
Depending on the implementation:

[ul][li]“Diagonal edges” are still edges, so the zombie can attack the player (who is occupying an edge tile). When the vehicle rotates, the player can always be attacked if adjacent to a zombie in global coordinates.[/li]
[li]“Diagonal edges” are interiors, so the zombie can’t attack the player, despite vehicle not being rotated and player being adjacent to the zombie[/li][/ul]

Example of the “player can always be attacked when adjacent in global coords”:

. | | .
. | @ |
z | | |

Rotated to:

| | . . .
. | @ | .
. z | | |

The lack of the tile diagonal to the player would cause the tile on the other side to be valid to attack from.

And once again, we still need that ray in some cases, because “can’t attack” isn’t a good enough answer, we need “so what should we attack instead?”.
So the neighborhood information would only allow skipping the un-rotation check (relatively cheap operation).

Optimization isn’t all that important in zombie vs. vehicle attacks. Could be nice to have, but a simple, easy to understand solution is more important here, as car bashing doesn’t happen all that often. And when it does happen, it’s usually an unrotated car which is attacked, so the idea for implementation in my post above would be quite fast (distance would always be 1, no rays would be cast).

Good catch. Seems like a raycast is probably the way to go then.

And what would you do with the rotated vector?
We still need an alternate target for the zombie, so that it doesn't just stand still, trying to attack a player behind "diagonal vehicle forcefield".
There could be some different solution, but casting a ray and considering attacking the second and third tile of it would be a relatively simple solution.
I kinda meant the same thing. You rotate the attack/movement vector and get new target. Since for most zombies these are 1-tile ranged, it's mostly getting and rounding it all. You can do it by raycasting, but that's stupid to cast a ray for 1-tile ranged action when you can basically just {target_x = x0 + round(cos(angle)); target_y = y0 + round(sin(angle))} which should (will) yield the exact same result as raycasting but far more simpler and less CPU-time consuming. It's not something to worry about in this situation, though. If instead of angle we have coordinates of the end of the vector, we can instead use a little more: {target_x = x0 + round((1/vector_length)) * (x1-x0), target_y = y0 + round((1/vector_length) * (y1-y0))}. I'd say raycasting should be used to the get first object to hit rather than merely getting new coordinates.

You’d save some CPU time where we have plenty, but in exchange you’d complicate the code (not simplify it) with extra angles to pass around and trigonometry where none is required. And the results wouldn’t necessarily always be identical due to how bresenham algorithm works (it doesn’t use trigonometry internally), meaning zombies wouldn’t always bash in the direction they’d want to go.

Meanwhile casting rays can be as simple as line_to(from, to, 0) (making fixing bugs easier), would be consistent with everything and wouldn’t introduce any noticeable performance loss. Overall much better solution.