The refactoring of terrain from int to a game object is about half done. No big surprises, but the entire structure of Level and map is a bit complicated. I guess it's supposed to be, because it's not a simple thing.
The call hierarchy to the actual terrain object is in most cases Level - Level_Map - Tile - U_Terrain (the last class is the terrain object instance). Not only that, the U_Terrain also includes the static data class for terrain, named K_Terrain_Type. In most cases Tile is using most of static data information so to avoid some wrapper functions I made U_Terrain the friend of Tile in which case getting information from static data looks like this:
It's always a problem in class programming to decide the structure of functions that handle something. In ideal case you can avoid simple getters, but in real life.. well, they do happen once a while. I think it's important not to care too much about "bad" structure, rather than concentrate on making things that work in gameplay level. No one cares how bad the source code is if the game is great. Also, I think in most cases it's a matter of preference where the action happens. If you want to limit the action to a low level class then you have to pass more information in that class. Or the other way is get more information in smaller pieces using getters.
This refactoring has been a lot easier than I thought, mainly because Tile class was already there and the "only" thing to change is simply add terrain object to Tile instead of int type. Of course it's not that simple if you want to make bigger changes in the concept of terrain as just another object type.
There is also a kind of struggle with other game objects. At the moment objects are stored in lists, but they could also be owned by the Tile itself as the terrain object is now. Tile is using only object pointers for easier access to object in that tile, but it could also own the objects, now that terrain is owned by it.