Larger building prevent elevated roads. But it is possible to build elevated roads over tiny buildings.
As a city grows the building get renovated and it arise taller buildings.
Elevated roads do not prevent larger buildings from appearing beneath them when the buildings are renovated or rebuilt, which results in a visual mess. Even though that doesn't interfere the game.
I just wanted to mention that. Maybe just exclude building under elevated road from renovation.
I checked this in the code, and makie's report is correct: the height check only works in one direction.
What happensWhen an elevated way is built,
way_builder_t::is_allowed_step() rejects buildings that have graphics at height 1. In practice, this is Simutrans' current definition of "too tall".
City renovation does not perform the same check.
stadt_t::renovate_city_building() selects a replacement by level, type, climate and date, but never checks whether an elevated way already exists above it.
This means a low building can legally receive an elevated way and later be renovated into a building that the player would never have been allowed to build the way over.
ReproductionUsing pak128 2.10.1, I grew a city underneath an existing elevated way until 1990:
- 219 renovations occurred below the elevated way
- 93 selected a building with an upper storey
- the first invalid replacement appeared at level 25
The order is important: the elevated way must be built first over low buildings, and the city must grow afterwards.
Attached patchRather than completely preventing renovation, the patch only removes buildings that are too tall from the list of possible replacements.
It introduces a shared
has_upper_storey() check, used both by the elevated-way builder and city renovation. This avoids having two separate definitions of what is considered too tall.
If no suitable replacement exists, renovation already returns without changing the building, so no additional fallback logic was needed.
With the patch, the same test produced:
167 renovations, 0 buildings intersecting the elevated way.The area still developed normally and reached level 52 of pak128's 59 levels. The upstream test suite also passes: 201/201.
ScopeThe patch only applies to
monorailboden, which covers elevated roads, railways, monorails, maglev and tramways.
Bridges are intentionally not included. Bridge construction currently allows tall buildings underneath them, so changing that would be a separate gameplay decision.
The remaining question is whether this restriction is desirable for every pakset. I tested pak128, but other paksets may have a different distribution of low-rise buildings at higher levels. I am happy to adjust or drop the approach if this behaviour is not wanted.
This is long time problem.
Also trees appear beneath them. And it looks very strange when elevated way (not only roads, but also railways and other ways like monorails and so on) is crossed by anything that is placed beneath them.
I think that it is caused by that objects may be a bit higher than 1 tile even if their height is still in range of 1 tile. But game is not capable identify this height exceeding - even if objects higher than 1 tile don't appear beneath elevated ways.
Also something important to keep in mind for a possible "fix" is. What if it is more than 1/2 steps above a building? What if it is 8 steps above? Technically the allowance should be dependent on the height of the building, not if the building is higher than double height or something
A bridge or elevated road at 2 steps over a skyscraper is weird, but if the bridge/elevated way is higher than the skyscraper is than it shouldn't be a problem, heck it might even be desirable
Thanks for the ideas, they are useful and I agree that a proper height/clearance system would be the better long-term solution.
The patch I attached is intentionally much smaller: it just fixes the current visual inconsistency by making city renovation use the same rule already used when building an elevated way.
A real height-based solution would be a much bigger change, affecting city growth, paksets and probably other elevated structures too. Before going down that road, I think it would be better to have prissi or another code integrator confirm that this is the direction they want.
For now, I would keep this patch focused on the reported bug, but the wider idea is definitely worth discussing
There are even special building addons on the japanese wiki tailored to fit exactly under elevated roads. The only proper solution is a new flag for buildings for makeobj, like the underground flag, because even single height buildings could be way too high. (And pak128 Schwebebahn is another issue graphically ... )
As a compatibility measure, one could flag all old buildings on load time with this flag depending on their height. Then monorails could be constructed also over such buildings.
And in principle, the bridges should do the same test. Moreover, I have an unfinished patch for more than single level high elevated ways, like extended has as well. So a building height flag parameter is very useful.
So my idea would be:
Introduce a new parameter for buildings in dat files: "height_clearance" with a default of -1 (meaning not set, whcih is also the default for old versions)
On load time in hausbauer_t::register_desc
height_clearance == -1 => check tile image of (0,0) or right upper corner for height.
height_clearance=min(0,(pak_size/2-ymin)/height_step) and so on for heights higher than 1 add the offset of the lower tiles and just take the height directly. That would avoid most graphical errors and give most flexibility.
And apply this height clearance also to bridges during renovation because it should apply there too.
A little longer is the effort to change bridge builder and way builder for elevated way, which would be needed anyway for more freely constrcuted elevated ways. I would put this off for now, as such changes are very prone for errors and I would rather release something stbale soon.
Adding a new makeobj flag and checkign height of buidlings on load is quite stareight forward and you did most of the work already.
It sounds interesting; in fact, this was discussed years ago. Back then, the goal was for planes to recognize the height of buildings using a flag, as @prissi mentioned, to prevent them from aircraft through buildings like ghosts.
Of course, implementing this logic for planes could be difficult and complex, but it would be nice to have more realism in this context.
Quote from: prissi on July 20, 2026, 02:30:02 AMSo my idea would be:
Introduce a new parameter for buildings in dat files: "height_clearance"
I think the idea is good, though also a bit involved.
I would also like to point out that, for multi-tile houses, the check currently only covers tile (0,0), as it appears to me during testing. I didn't look at the program.
My idea was much simpler: to prevent
the city from automatically building and renovating under bridges, elevated roads and similar structures, and to leave the rest up to the player.
Not sure if completely disallowing the build/renovating buildings under bridges is really desirable... That would mean that if the player does not have access to the public player they can't add buildings underneath the bridges/elevated ways.
Quote from: danivenk on July 20, 2026, 09:32:46 AMNot sure if completely disallowing the build/renovating buildings under bridges is really desirable... That would mean that if the player does not have access to the public player they can't add buildings underneath the bridges/elevated ways.
My concern is the city itself, which simply and stupid builds anywhere as it expands—including underneath elevated highways.
What the player does is a different matter. To restrict the player in a single-player game, it makes only sense if it is absolutely necessary to avoid program crash, I think.
prissi, the height_clearance parameter looks right to me, and more useful than what I posted: it names the property on the building instead of deducing it at each call site, it covers bridges and future multi-level structures in one place, and the -1 auto-detection means paksets get it without editing a single dat. If you want it implemented I am happy to do it — say the word and I will work to your formula rather than invent my own.
One question about it:
height_clearance = min(0, (pak_size/2 - ymin) / height_step)This is always less than or equal to 0 as written. Did you mean max?
Two clarifications about the patch I attached earlier, because I think the thread is partly arguing against something it does not do.
Multi-tile buildings. makie, you are right that this needs checking, and it is why the patch adds two predicates rather than one: building_tile_desc_t::has_upper_storey() for a single tile, and a building_desc_t counterpart that asks it of every tile across layouts * size.x * size.y. Renovation uses the second, so it does not stop at (0,0).
The way builder still uses the per-tile one, which I believe is correct there since it walks the tiles the way actually crosses — but that is also the path where I would expect a (0,0)-only symptom to show. I have not reproduced what you saw, so if you can say which of the two it was, I will test it properly rather than guess.
Blocking the player. danivenk's objection is a real one, but it does not apply to this patch: the only behavioural change is inside renovate_city_building(). Nothing a player can do is refused that was not already refused before. That is deliberately makie's last post — the city, not the player.
And it forbids nothing even there. The flag goes into the candidate search beside the existing climate, size and exclusion filters, so the block keeps renovating and simply stops growing upwards once the pakset has nothing suitable left. The alternative — freezing those tiles — would leave a stripe of untouched buildings under every viaduct as the rest of the city modernises around them.
None of that is an argument against height_clearance, which subsumes it: my has_upper_storey() is just the -1 auto-detection collapsed to a single height level and hard-wired to elevated ways. I would rather have yours.
Separately, on Václav's point about trees: that one is a drawing bug with a cause of its own, and I have opened a thread for it rather than mix it in here. It is relevant to this discussion in one small way — the fix is a unit error in exactly the arithmetic being discussed, and it divides by the height step, same as your formula does.
Quote from: makie on July 20, 2026, 09:44:09 AMMy concern is the city itself, which simply and stupid builds anywhere as it expands—including underneath elevated highways.
What the player does is a different matter. To restrict the player in a single-player game, it makes only sense if it is absolutely necessary to avoid program crash, I think.
I get that, but even then that means if a different player real or AI could technically cut off growth by just building an elevated way or bridge next to a city. I'm just posing possible concerns with completely disallowing it. Hence why I myself am not sure if such a quick fix is the right option. That is why I think that either prissi's idea of introducing height into the objects or a way of estimating the height of a building based on how many tiles it covers in the drawing phase is the best option.
IMO of course
Quote from: danivenk on July 20, 2026, 11:22:30 AMif a different player real or AI could technically cut off growth by just building an elevated way or bridge next to a city.
Every railway and also all fences do this.
Some cityrules allow jump over one railway if there is station but if you build a double railway around the city then the city can't grow anymore.
This is nothing special to elevated highways.
QuoteMy idea was much simpler: to prevent the city from automatically building and renovating under bridges, elevated roads and similar structures, and to leave the rest up to the player.
Since there are bridges over entire valleys with villages, I think a general ban is not nice, and height related is better.
Quoteheight_clearance = min(0, (pak_size/2 - ymin) / height_step))
Height zero is exactly at half height. Image coordinates are from top left. The smaller ymin, the more height needed. Hence the minus sign. Starting deeper than half height needs no clearance, and then one more per height_step. I agree that zero does not make sense, one should better calculate:
min_height_clearance = 1 + min(0, (pak_size/2 - ymin) / height_step))
With a flag in desc, multitile buildings shoudl be fine, since the desc is the same for all tiles.
say the word and I will work to your formula rather than invent my own.You prepared already a lot of the needed work. So maybe just go on? I am very busy this week at work, I fear, lots of text to write, which drains me and do not leave enough for programming.
Quote from: victor_18993 on July 20, 2026, 10:22:55 AMMulti-tile buildings. makie, you are right that this needs checking, and it is why the patch adds two predicates rather than one: building_tile_desc_t::has_upper_storey() for a single tile, and a building_desc_t counterpart that asks it of every tile across layouts * size.x * size.y. Renovation uses the second, so it does not stop at (0,0).
The way builder still uses the per-tile one, which I believe is correct there since it walks the tiles the way actually crosses — but that is also the path where I would expect a (0,0)-only symptom to show. I have not reproduced what you saw, so if you can say which of the two it was, I will test it properly rather than guess.
Ok it seems it depend of the graphic.
This is a test without your patch. Try to build a elevated way over a 2x2 Building.
Pak128.german
tile (1,1) elevated way can always build
tile (1,0) and (0,1) only if the graphic is lower at this tile
(https://makie.de/4x4-ev.png)
same after rotate 180 degree
(https://makie.de/4x4-evr.png)
I think the highest point of the graphic should apply to all tiles.
The highest point should be always on the backtile, and, if the patch uses the formula I proposed, it would only allow brdiges higher than this point. (Unless specified explicaitely in the dat file.)
I have put the whole fix into a single patch on r12094 (7 files, test suite
201/201). Here is what it does, in plain terms — the numbers and the reasoning
are in the attached document for anyone who wants them.
What was wrongTwo things, which looked like one:
- The city keeps renovating the houses under an elevated road or railway, and
sooner or later grows a tall one there — one the game would never have let you
build the elevated way over in the first place. - Even when a tall building or a tree is under an elevated way, its top draws
straight through the deck instead of being hidden behind it.
What the patch does- The city no longer picks a building that is too tall for the space under an
elevated way. It keeps renovating normally — it just stops growing upward there,
so you get a low-rise strip under the viaduct, the way a real city looks. It only
changes what the city does on its own; it never stops you, the player, from
building anything. - Anything that is under an elevated way is now cut off cleanly at the deck, so
it no longer shows through. This was already meant to happen in the code — there
is even a comment about it — but it had quietly stopped working. It fixes it for
trees and for buildings at the same time, and for bridges as well as elevated
roads and rails.
Good to know- No pakset needs changing. The building heights are worked out automatically
when the game loads, so every existing pakset just works, and nothing needs
recompiling. - Tested on pak128 and pak128.german, in game.
For prissi — I built the automatic height detection from your
height_clearance idea. Measuring across three paksets showed something worth
flagging: if that height is used to
forbid elevated ways, it blocks
94–100% of all city buildings, because honestly measured they really are as tall
as the deck. So I use the measured height only to
hide what pokes through,
and keep the old permissive test for deciding placement. I left out the .dat
parameter and the way/bridge builder changes — those are the parts that affect
compatibility and what the player may build, so they are your call. The full
reasoning, the measurements and how each part was verified are in the attached
document.
I checked for pak64, and a far lower number was affected, maybe because pak128 uses half heights while pak64 uses double heights as does pak128.German. (I.e. only pixel start at 15 and lower needed two height clearance). Given the low heights of elevated ways in pak128, I think it is fine if only parking lots are allowed below.
I think the height calculation is only done once and thus, no special routine in desc would be needed, as haubauer_t is anyway a friend of building_desc_t and thus can modify private data. (But this is probably my progarmming style only.)
For simcity, I would rather check the height above a plaquadrat, that is very fast.
Quoteconst planquadrat_t* plan = welt->access(pos);
sint8 max_h = 127;
sint8 base_h = gr->get_hoehe();
for (int i = 1; i < plan->get_boden_count(); i++) {
grund_t* test = plan->get_boden_bei(i);
sint8 diff_h = test->get_hoehe()-base_h;
if (diff_h > 0 && diff_h < max_h) {
max_h = diff_h;
}
}
and feed this parameter to the city building selection rules, as it is more future proof.
The display routines are VERY time sensitive. Avoid things like dynamic cast (not needed) and traversing tile lists, as this is EXTREMELY slow as almost every tile is a cache miss. Hence my suggestion of using the allowed high from desc for all tiles.
Thank you, that makes the intended architecture much clearer.
I like this approach better. Separating the problem into building selection and rendering also makes the patch cleaner.
For city generation, I'll compute the available vertical clearance from the planquadrat and pass that limit into the city building selection, so unsuitable buildings are filtered out before they are even considered. That should also make it naturally work with bridges and any future multi-level structures.
For rendering, I'll move away from any runtime height detection. I'll calculate the building's visual height once when the descriptor is registered, store that value in building_desc_t, and then only use the cached value during drawing.
For pak128 I'll also keep the behaviour conservative, so only buildings that actually fit beneath the elevated way (such as parking lots) can be selected there.
I'll rework the patch following this design and test it with pak64, pak128 and pak128.German before posting the next revision.
Thanks for the detailed explanation.
Thanks, prissi. I have reworked the patch following all three points you raised. It is based on r12094, the test suite still passes 201/201, and I have checked it in-game with pak64, pak128 and pak128.german.
Display: no more dynamic_cast.
The clipping loop now checks
o->get_typ() == obj_t::gebaeude, uses a static cast, and reads the cached
height_clearance value from
building_desc_t. There is no longer any height calculation in the drawing path.
Building selection now uses the available clearance from planquadrat.
renovate_city_building() calculates the distance between the ground and the nearest upper layer:
sint16 max_clearance = 127;
if( const planquadrat_t *plan = welt->access(k) ) {
const sint8 base_h = plan->get_kartenboden()->get_hoehe();
[pre][code]for( unsigned b = 1; b < plan->get_boden_count(); b++ ) {
const sint8 diff_h =
plan->get_boden_bei(b)->get_hoehe() - base_h;
if( diff_h > 0 && diff_h < max_clearance ) {
max_clearance = diff_h;
}
}
[/pre]
}
[/code]
That value is passed into the city-building selection, which only keeps candidates whose
height_clearance fits within the available space.
This also covers bridge decks and future multi-level structures. A higher deck naturally allows taller buildings, while a value of 127 means that there is nothing above the tile, so normal city growth remains unchanged.
Building height is calculated once and cached.
The value is calculated when the building descriptor is loaded and stored in
building_desc_t. For buildings with several tiles or layouts, it uses the tallest tile, covering the multi-tile case mentioned by makie.
Pak128 behaviour.
With the measured values, only genuinely low buildings such as parking lots fit beneath the lowest elevated ways in pak128. Anything that still extends through the deck, such as an existing building, a monument or a planted tree, is clipped at deck level and is no longer drawn through the elevated structure.
I intentionally left the way builder unchanged. It still uses the existing
has_upper_storey check when deciding whether the player may build an elevated way over a building. Replacing that with the same measured-height logic would also change gameplay, so I considered it a separate decision.
The detailed measurements for each pakset, together with the verification steps, are included in the attached document.
Thanks again for the detailed guidance.