-
Notifications
You must be signed in to change notification settings - Fork 4.4k
fix grabbing dig you down #82700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix grabbing dig you down #82700
Conversation
The purpose of the update_map() stuff is to keep the PC at the center submap of the reality bubble at all times. Any movement of the PC that takes the PC out of that submap should result in the reality bubble being shifted to center around the PC's reality bubble submap. I don't know what the consequences of removing the code are. Maybe the next movement of the PC causes the shift to happen then (while the reality bubble remaining lopsided until that happens), in which case the damages are limited as long as the distance moved is short. However, this cannot be accepted without an analysis of what the consequences would be. If update_map() calls gravity_check() somewhere it would cause the target to fall on the in-air pull that crossed a submap boundary, only to have the position being returned to the air (but, presumably, still taking damage from the fall). I fail to see where this causes the PC to end up underground (which shows there's something lacking in my reading of the situation, not that the bug cannot occur). The crux here would be tracking of the PC's Z level and the call chain of it dropping below ground in particular. |
I actually tried to debug the try_fall() function that respond for character falling, but what i debugged made me super confused Lines 10079 to 10092 in 3d07400
|
That's definitely weird. That code could be changed to test for a creature at "below" rather than "where" and decrement both only when past that point rather than decrement and then increment "where" on a bailout, but assuming the compiler works correctly, it shouldn't change the result, as far as I can see. Having try_fall take the position of the creature as well as the creature is also weird, but the call we're interested in seemed to feed in pos_bub() of the critter, which, again, wouldn't matter. "below" isn't updated in lockstep with "where" after its last use, but that should at most cause the two to become equal for the case where the PC falls on a critter. The PC is eventually moved by g->vertical_move() which is controlled by "height". That code takes the PC's current position rather than a parallel position position, but as far as I can see all calls to try_fall() just gets the current position of the critter, and so should work out. It can be noted vertical_move() is called with "force" being true, which is probably what allows the PC to be placed underground, but the "height" value shouldn't have made that possible, OK. I think I've found where things go wrong in this crowd surfing situation. In vertical_move(), on the second call (when crowd surfing) there's a weird calculation of z_after, which returns -1 rather than 0, and that's later used to set the Z level. There's even a TODO comment, but no reason for why it hasn't been done rather than just writing a comment. So, the problem seems to be that vertical_move() contains a hack to avoid the PC being placed under a zombie (with a cryptic comment about the correct code, but no mentioning of why the wrong code is there), but correcting that code causes the the PC to end up under the zombie and become invisible (the zombie is critter displayed). I still think that's less bad than ending up underground, though. It can also be noted that the PC isn't invulnerable in that location: if attacking (and presumably doing anything advancing time) the PC is killed by the surrounding zombies. Edit: I debugged a roof on the other side of the horde (but on the same submap), teleported there, and then waited. The result was that the PC was dragged down and ended up invisible under a zombie, but without any call to vertical_move(). Given that this happens in the regular case, I don't see any reason for not fixing the weird miscalculation of z_after so the behavior is consistent. Of course, there might be some other reason for the weird miscalculation... |
I still think it's because of #78254, there's no this kind of issue before it. Edit: If its because of gravity check, why not to just try deleting the added gravity check here by #78254 |
@rtxyd: Well, removing that call causes the PC to crowd surf in the bug report save, but what happens when the grabber stands in a window of an above ground level floor of a building? I would expect that would cause the PC to levitate outside that window, which would shift the problem there instead. The root cause of the trouble is that there is currently no good way of handling the case of the PC ending up on top of a sea of zombies. The corrected vertical_move() code causes the PC to end up in the same tile as the zombie. There is code in try_fall() that moves the zombie to the PC's place above it, but apparently the zombie falls down on top of the PC when it gets processed. Changing try_fall() to give up when the critter fallen upon cannot be pushed to the side and leave the PC crowd surfing in that case, e.g. by replacing
with
would leave the PC crowd surfing while not messing up the other cases where a gravity check is warranted. |
So what's your opinion @PatrikLundell? is it okay to merge it in this state, or there should be some different approach? because again, i tested it manually, and i didn't saw something that would make me instantly think it's a bad idea |
Unfortunately, I still think it's a bad choice. It removes functionality because of a side effect in it, and it's unclear what the effects of removing the functionality are. I would expect obscure bugs that are hard to track down, because the reality bubble generated by a loaded save isn't the same as it was when the save was made. I still think there are two main alternative soultions:
There is also the expansive option of trying to deal with crowd surfing for monsters on monsters and PC on monsters of option 2. How? I don't know. Maybe find a way to allow multiple critters on the same tile, but that is probably quite a task, including the need to show it graphically. |
How about my previous suggestion? Though your concerning is true, but when the grabber is on the edge and pulling you its certain that its the only monster on the edge, and as the physical force keeps inflicting by it during the grabbing, I think its reasonable to levitate at the mid-turn of the whole grabbing procedure (if it finally grabs you up to the next floor). |
@rtxyd: I think changes to #78254 are better discussed with the author of that PR. However, as a minimum I'd expect you to test the current implementation against your proposed change in a variety of situations to verify the results are reasonable in all of them. Note that the call is done after the dragger has pulled its victim to the final destination for that turn, and I believe that destination is adjacent to the dragger, not to the dragger's tile, which would mean hovering in the air when the dragger is at the edge of a ledge (ending up above the dragger presumably only happens when there's no free tile adjacent to the dragger on the same Z level). Now, you could argue that the dragger presumably is still holding on to the victim, thus preventing it from falling, but you'd end up with a number of oddities that would need to be checked if that's the case.
|
I don't have the total context, but Patrik is right that update_map MUST be called ASAP if the player is moved out of the central submap of the map. The player always being in that central submap is a bedrock assumption made throughout the code and there's no telling what will break if that assumption is violated. |
Summary
None
Purpose of change
Fix #79854
Generally grabbing calculate gravity check once, in the end, but not when grabbing moves you across a tiny map, in this case grabbing calls map update, which itself calls a gravity check. For magical reason calling two gravity check dig you down one level below
Describe the solution
Remove manual map update - undocumented and unexplained, i don't really know why it was here in the first place
Describe alternatives you've considered
Make grabbing more 3d aware - currently it just moves you in two dimensions and then just rely on gravity check for you to fall down
Find why calling gravity check twice do not update the character position properly - good approach, but try_fall() code is terrible, barely explained, and i have difficulties following it
Testing
Used my test where i had a setup that digged me under the ground quite often, saw zero cases of me digging down, also saw no another oddities, which made me think it's safe to backport it
Additional context