My algorithm for this, which is based on the rpg-naker XP:
const auto zPos = vScreenPos.y + 32.0f;
static constexpr auto DIVISOR = 0xFFFFFF; // could be manually tuned depending on the number of objects and size of screen
const auto z = 0.5f + zPos / DIVISOR;
So essentially, for each pixel that the object is lower on the screen, it gets an every increasing “z” value. 0.5f in my example is used as the neutral “center”. Certain effects can then be achieved by placing other sprites at static values relative to those (0.499f for something that is in the background, ie).
For how to do the actual sorting: If you only have opaque or cutout-sprites, you can just have a zbuffer and need to real sorting, just assign the sprite this z-value. For transparent sprites, you just manually sort based on this, but you should still use a zbuffer with different settings (write for opaque, read for transparent).