Attempts to change this default behavior result in weirdness.
turf/allowowner
var
owner
Enter(atom/movable/o)
if("\ref[o]"==owner)
return 1
else
return 0
The above would mean that Cross() would never be called for anything in the tile at all. This means that the owner could enter the turf, overlapping objects that should prevent them from overlapping that tile.
The correct way to do the above is:
turf/allowowner
var
owner
Enter(atom/movable/o)
return ..() && "\ref[o]"==owner
The other issue, is that this makes looping over a list returned by obounds() or the like unnecessarily difficult to test for collision:
for(var/atom/o in obounds(ref))
if(isturf(o))
if(!o.Enter(ref,ref.loc))
return 0
else if(!o.Cross(ref))
return 0
return 1
The other issue with this snippet, is the fact that Cross() will be called twice for some atoms, because that behavior is built into Enter().
Instead, I propose changing Enter()/Exit()/Entered()/Exit()'s default behavior:
Call src.Cross(o). If 0, eject early. If non-zero, search through full-tile blockages calling object.Cross(o), if zero, eject early. If exhausted, return 1.
Entered()'s default behavior should be to call turf.Crossed(o).
This change will result in looping over bounds lists much easier and saner:
for(var/atom/o in obounds(ref))
if(!o.Cross(ref))
return 0
return 1
No duplication problem here!
As well as not break any existing code, as existing projects will simply have either not used Cross() on a turf, or will have overridden Entered() without calling default behavior (because there was none), thus choosing to eliminate Crossed() and Uncrossed() calls from their project.
The other positive result, is that turf/Cross() and turf/Uncross() can be quick overrides that you don't need to know deeply how they work:
turf/allowowner
var
owner
Cross(atom/movable/o)
return "\ref[o]"==owner
The above code would prevent Cross() checks from being called on objects in the tile, which would be consistent with the intended way that object collision priorities should be sorted: turf first, full tile objects second, objects with lesser coverage third.
The problem with this, is that for any turf that you have overridden the default density rules, the turf actually needs to have a density of 0, or you have just destroyed the turf's ability to consider objects blockages and will have to completely rewrite the code to handle that by hand.
If the object does have a density of 0, though, that means that things using built-in pathfinding will try their damnedest to pathfind through the tile, even though they can't move into it at all, thus globally breaking built-in pathfinding for your project. (yay!)
This means that the object-checking behavior should happen in turf/Enter(), but the turf's density should be considered as the default action of turf/Cross():
Which means that instead of directly checking the density in Enter() to determine whether we check objects for Cross()/Uncross() behavior, we actually use turf/Cross() and turf/Uncross() to determine whether that loop happens or not.
Simple change, no project-breaking bullshit, huge quality of life improvements for everyone.
So the proposed global default behavior ought to look something like this:
Ideally, though, turf/Enter() would also handle area entry in Enter() to make certain that all "on the map" behavior is rooted on turfs, but that would involve complex checks in Enter() to make sure the player isn't in an area before testing turf.loc.Cross(), which is probably not desirable.