Aleph-One-Marathon / alephone

Aleph One is the open source continuation of Bungie’s Marathon 2 game engine.
https://alephone.lhowon.org/
GNU General Public License v3.0
654 stars 99 forks source link

Impassibility info goes out of date after some polygon height changes #515

Open Hopper262 opened 2 months ago

Hopper262 commented 2 months ago

In order for a player to be blocked by a tall ledge, two things appear to be necessary:

  1. A side must exist on the player's side of the line
  2. The line must be in the player polygon's list of line exclusion zones (see line_exclusion_zone_count)

When using Lua to change a flat multi-polygon area into a stepped or walled-off area, condition 2 prevents collision from working as expected. The exclusion lists are only calculated during map load based on the current polygon heights, in find_intersecting_endpoints_and_lines (and in turn, intersecting_flood_proc).

Steps to replicate:

  1. Start Waterloo Waterpark (preferably with monsters removed/disabled for simplicity)
  2. Raise the height in part of the starting area: > Polygons[336].floor.z = Polygons[336].floor.z + 0.4
    • you can stand too close to that polygon, and will step up to it even though it's too tall
  3. Create a side on the southeast line: > Sides.new(Polygons[331], Polygons[336].lines[1])
    • no change
  4. .save level and leave
  5. open the saved copy
    • south side now blocks the player, north side is unchanged
  6. Create a side on the northeast line: > Sides.new(Polygons[330], Polygons[336].lines[0])
    • north side now also blocks the player

If after all this, you reset polygon 336's floor to its original height, things behave normally. To further test this, I hacked the height checks out of intersecting_flood_proc and I was able to move about the level fine, though I didn't test much. I expect this sends the physics engine through many more checks than if one assumed static heights.

Updating an exclusion list is awkward because it's stored as a contiguous subset of a single flat list. Also, figuring out which lists are impacted isn't trivial, since it's usually but not always limited to the changed poly's immediate neighbors.

treellama commented 2 months ago

The height changes are indeed really only useful for small changes to the heights of polygons, or manually moving platforms. With the redundant line recalculation in effect, this also extends to opening/closing doors. Inflating something meaningful from a totally flat level would be cool, but wasn't really in scope for the polygon height variables.

Forge is able to do this (or is it?)--is it rebuilding the entire exclusion list? Or maybe using its own intersecting_flood_proc?

We're reaching the limits of some of the other map indexes. I am investigating ditching them entirely for sound objects, and using boost::geometry to quickly locate nearby polygons. So one option is to split exclusion zones into easier to manipulate data structures, as a precursor to fixing this.

Another is to add a Lua function which can completely rebuild the exclusion list, although that will still be jammed in by map indexes so those will all have to be recalculated.

Hopper262 commented 2 months ago

I haven't tried Forge but I am really curious now. Maybe it only ever worked to change a poly or two and then leave before you saw the consequences!

Hopper262 commented 2 months ago

With the redundant line recalculation in effect, this also extends to opening/closing doors.

Does this mean it's possible to manually open a fully-closed door using Lua height changes? I can't get it to work, but I'd love to be proven wrong.