I would do it like this (I haven't coded in C or Java for more than 5 years, and I'm not a programmer by profession, so excuse my syntax):
struct WeightDistrib {
byte weight; // the weight of the tile
byte below, above, ground, ceiling; // the supports from the tiles from below and from above
byte north, south, east, west; // supports from the tiles on the sides
}
WeightDistrib tileWeights[xMax][yMax][zMax]
WeightDistrib floorWeights[xMax][yMax][zMax]
and then when a tile is destroyed, I'd check all neighboring tiles if they are supported by the following function:
bool IsSupported(WeightDistrib currentTile, int x, int y, int z) {
int supportedWeight;
supportedWeight = 0;
if (IsThereObject(x-1, y, z)) supportedWeight = supportedWeight + currentTile.west;
if (IsThereObject(x+1, y, z)) supportedWeight = supportedWeight + currentTile.east;
if (IsThereObject(x, y-1, z)) supportedWeight = supportedWeight + currentTile.south;
if (IsThereObject(x, y+1, z)) supportedWeight = supportedWeight + currentTile.north;
if (IsThereObject(x, y, z-1)) supportedWeight = supportedWeight + currentTile.below;
if (IsThereObject(x, y, z+1)) supportedWeight = supportedWeight + currentTile.above;
if (IsThereFloor(x, y, z)) supportedWeight = supportedWeight + currentTile.ground;
if (IsThereFloor(x, y, z+1)) supportedWeight = supportedWeight + currentTile.ceiling;
return supportedWeight > currentTile.weight
}
int DestroyObject(int x, int y, int z,) {
ObjectTile(x, y, z).Exists = False;
if ( !IsSupported(tileWeights[x-1][y][z], x-1, y, z) ) DestroyObject(x-1,y,z)
if ( !IsSupported(tileWeights[x+1][y][z], x+1, y, z) ) DestroyObject(x+1,y,z)
if ( !IsSupported(tileWeights[x][y-1][z], x, y-1, z) ) DestroyObject(x,y-1,z)
if ( !IsSupported(tileWeights[x][y+1][z], x, y+1, z) ) DestroyObject(x,y+1,z)
if ( !IsSupported(tileWeights[x][y][z-1], x, y, z-1) ) DestroyObject(x,y,z-1)
if ( !IsSupported(tileWeights[x][y][z+1], x, y, z+1) ) DestroyObject(x,y,z+1)
if ( !IsSupported(floorWeights[x][y][z], x, y, z) ) DestroyFloor(x,y,z)
if ( !IsSupported(floorWeights[x][y][z+1], x, y, z+1) ) DestroyFloor(x,y,z+1)
Return 0
}
int DestroyFloor(int x, int y, int z) {
FloorTile(x, y, z).Exists = False;
if ( !IsSupported(floorWeights[x-1][y][z], x-1, y, z) ) DestroyFloor(x-1,y,z)
if ( !IsSupported(floorWeights[x+1][y][z], x+1, y, z) ) DestroyFloor(x+1,y,z)
if ( !IsSupported(floorWeights[x][y-1][z], x, y-1, z) ) DestroyFloor(x,y-1,z)
if ( !IsSupported(floorWeights[x][y+1][z], x, y+1, z) ) DestroyFloor(x,y+1,z)
if ( !IsSupported(tileWeights[x][y][z-1], x, y, z-1) ) DestroyObject(x,y,z-1)
if ( !IsSupported(tileWeights[x][y][z+1], x, y, z) ) DestroyObject(x,y,z)
Return 0
}
In this case what I'd do is in case of a destroyed floor tile, I'd check neighboring floor tiles, the object "on" the floor and "below" the floor. In case of a destroyed object tile, I'd check the neighboring tiles, the tiles above and below, and the floor tile on "below" it, and the floor tile "above" it.
In this I am having some assumptions about the data structure, most importantly, that floor and object tiles are in separate 3 dimensional arrays, with the floor below the certain object go by the same z coordinate.
Edit: I was thinking about only the weight of neighboring tiles as an approximation, so if you set it up that one pillar can hold a floor tile, and one floor tile can be held by one remaining neighboring floor tile, than this pillar will be able to hold an infinitely big floor by itself. But I think by tuning the weight and how it is supported on the sides, you could achieve an effect that the whole ceiling crumbles if one tile is missing, and you can also also you have one where you have to shoot all neighboring tiles to get the middle one destroyed.
This is how much I have thought about it now.