Cataclysm-BN
Cataclysm-BN copied to clipboard
Draw lower z levels
Summary
SUMMARY: Features "Draw in lower z levels."
Purpose of change
Fixes #1728. Draws in the contents of lower z levels with a visual effect.
Describe the solution
When drawing tiles previously each row would be collected and then drawn in turn. Now the whole map is collected first. It's during this collection that the searching down to lower z levels happens and only the lowest tile is collected. Collected tiles are sorted by z level, then the terrain, furniture, graffiti and trap layers are drawn for each collected tile in turn. Then starting at the lowest z level and working up, the fields, items, vehicles and creatures are drawn for each collected tile and the tiles above them. Lastly the zone markers and revival indicators are drawn.
Things being drawn on lower z levels have an effect applied to them. Similar to the greyscale and nightvision versions of sprites, a filter is applied that maintains the alpha channel and sets the color to a light cyan. When drawing the sprite this texture is drawn over the top of it using SDL_SetTextureAlphaMod to control transparency based on z level. There's an option to use a prebaked version of this with a fixed transparency instead.
When 3d field of view is turned on it takes into account visibility when looking downwards. If you don't have visibility on the tile below it will draw a small square like it does currently. This is also the case if you turn z levels off. When vehicles are being viewed from above like this they will prefer to show their roof part unless they have a creature in them.
Describe alternatives you've considered
Porting to UE5.
Testing
There are some cases that don't layer nicely. If a large sprite like a hulk is stood one tile south and down from a vehicle the hulk will be rendered below the vehicle making it look like it's shoved its head beneath it. I don't think this is easily resolved though. In this case the hulk should be on top, but if the vehicle covered a tile south as well, then it should be underneath as the vehicle should hide it entirely.
I'm not too happy with the way 3d fov looks, I think the squares look a bit out of place but flat cyan doesn't look any better. It also doesn't show car roofs as you can't see the tile with the part in it.
Additional context
Landed on a roof:
Same with 3d fov on:
there's this beige
path being left behind, i guess it has something to do with remembered maps.
https://user-images.githubusercontent.com/54838975/179726442-431f404a-24df-49a5-b34d-85db37b0e37c.mp4
Alright, that bug is fixed along with better handling for memory in general. Turns out memory was just ignoring the z value of the tripoints you gave it. That's no longer the case when z levels are on.
I fixed another bug that changing the option after the tileset was loaded caused misrendering. This behavior of force reloading the tileset when it changes has also been added to the map memory serpia/greyscale option so that it no longer requires you to restart.
Wow <3 Definitely worth porting back to CDDA
Looks good, I just need some time to understand how it works to be able to tell if there are edge cases that need specific testing. There is minor merge conflict in one of the files.
Performance: I see that you avoid re-drawing the tiles in some way. Does this make drawing time mostly independent on z-level difference? If not, an option to limit how far does drawing below go would be useful.
Minor code quality tips:
- Use
get_map
overg->m
where possible. If re-used multiple times, it's good to save it in a temporary, usuallymap &here = get_map();
. This helps with refactoring and avoids dependence on bloatedgame.h
. - If you're reusing one option a lot, it's a good idea to cache it.
cached_options.h
has all the cached options and they are actually set inoptions.h
. If you're reusing it only a moderate amount, using static strings (make_static.h
andSTATIC( "string_here" )
) helps avoid rebuilding the string every invocation.
Does this make drawing time mostly independent on z-level difference?
Yes, with the dynamic effect, 0 z levels is faster than 1 but 1 isn't faster than 7. The difference is a little more than 2x but this isn't going to be enough to impact most graphics hardware even phones.
That said the effect is capped at 7 z levels for visual reasons. The way it works is each z level is worth ~9% (24/256) opacity, except the first which is worth twice that much. This caps at 75% at 7 levels because higher opacity just makes it look like everything's been covered in blue paint.
There's another bug with map memory: it's not rendered if it's outside character sight range bounds + there is no tile memorized at character's z-level. Example pics from an apartment tower with save:
Spoiler
Upd: this is on ver. 752b8605, before the force-push a few minutes ago.
Good catch! I've done better handling for things outside of the map bounds. It's a bit of an awkward case as with that part of the map being unloaded we don't know where the floor is. As such it won't go lower than z level 0 in those cases to stop labs etc showing up above ground.
also, could you push instead of force-push? following commits step by step would be easier to read
I'm getting weird edge lines with 3D vision:
Those are seen as "below: grass", but rendered as dots.
There is a balance issue in that it lets player see the monsters below, but not the other way around. The simplest way to handle it would be to only render terrain, furniture and vehicles (stuff that is currently in map memory).
I'm sure people will ask about V
menu not showing the items that are below, so hiding items would be good.
Ideally, it would only show what player can see (in 3D), could see and remember (2D) and has actually remembered.
Other than those, I've seen no issues with it.
If it worked with map memory, we could allow player to look up/down in look mode. It's currently disabled if 3D view is disabled, but this means that player can't even review memory.
How does it apply to ASCII?
How does it apply to ASCII?
Right now it doesn't seem to apply at all. It should maintain parity. I'm not sure if the PR should be delayed until ASCII/tiles work the same way.
Still, monsters and items being shown graphically but "not truly seen" is certainly a blocker.
The edge lines were caused by seeing some tiles from that stack without being able to see the ground. To fix it you can now have half-remembered tiles. That is tiles where you're remembering the terrain and then actually seeing a presumably flying monster on top.
I've also removed the ability to see items and monsters in 2d however, it still doesn't have total parity with ASCII. ASCII only lets you see down a single z level and getting rid of that because it's not great for flying is part of the intention. So I'd like to go the other way and bring ASCII to parity with this.
2D vision, some item bits are still drawn:
This message is now more misleading than before:
It would be good to rephrase it to imply it's on the same level/story/[insert non-technical synonym for z coord].
I've fixed the final layers (i.e. revival indicators and zone markers) using the wrong source, they now use the player's z level rather than the terrain's.
Also rather than change the message on the items, I've made it so you can now just see them across z levels same as you can with monsters.
Also rather than change the message on the items, I've made it so you can now just see them across z levels same as you can with monsters.
That's a nice bonus!
Alright, let's give it a go.
Can this be backported to DDA?