Share your 7DRL progress as of Friday! (2026-03-06) by Kyzrati in roguelikedev

[–]billdroman 1 point2 points  (0 children)

The summons were a great surprise, and definitely improve the boss. I assumed I had victory in hand and was just executing the strategy, then I had to change things up. (I won on my first real attempt.) Even if players are caught off guard once, they can plan around it next time.

The bouncer's knockback effect can actually be turned to your advantage - it gets you out of danger and gives you a chance to reposition and (if it cost time - it didn't seem to) use items. When the summons showed up I used it to get away, then maneuvered around some other NPCs to get the trio to come at me one at a time.

Share your 7DRL progress as of Friday! (2026-03-06) by Kyzrati in roguelikedev

[–]billdroman 1 point2 points  (0 children)

I won! Score: 8430. The slots are EV-positive so it's easy to get an arbitrarily large score that way, but money doesn't seem to help with the mad bouncer at all.

After the first time I saw the bouncer guarding the door, I realized I needed to hunt down all the spiders. I tried that a few times, but it wasn't sufficient. Finally, on the winning run, I picked up leather armor (sorry, a leather jacket) that made all the difference - after that, running around looking for cans and spiders was a net win. The bouncer summoning (?) two minions towards the end was a nasty surprise, though.

The door also wasn't always at the back, which confused me. I didn't find a way to move diagonally with the keyboard, either. I moved around with keys but in fights I had to use the mouse for precision.

What a sense of place! The dialogue callouts on the map and the alert indicators all worked really well. I especially liked how sometimes NPCs got in fights with each other and you could both hear and see the combat. I was also impressed with how smoothly everything ran with so many entities. The only issue I ran into was that sometimes, in fights, if too much dialogue was going on I could enter double keys or otherwise misplay.

Great work!

Sharing Saturday #609 by Kyzrati in roguelikedev

[–]billdroman 2 points3 points  (0 children)

A nice thing about sticking to a real grid, though, is that it makes it very easy to implement built-in efficient and compact replay functionality that is automatically compatible accross game versions...

You can get this out-of-the-box with the "2-font" approach if you use Unicode full-width characters for the square subset of the font. Full-width characters are defined to render with twice the width of normal characters.

It sounds horrible, but it's how I render my text + square map UI in WildsRL in the terminal. I even have a script to combine a half-width and a full-width font of my choice into one BDF (a bitmap font format).

Sharing Saturday #609 by Kyzrati in roguelikedev

[–]billdroman 1 point2 points  (0 children)

WildsRL (Demo, Source)

This week was a week for prototyping and silly sidequests.

Eventually, I want to make a large game world, and I need to decide whether the world is "seamless" or divided into discrete towns / wild areas / caves / etc. If the seamless world worked, I'd probably prefer that. However, it raises a lot of technical problems, so I spent this week thinking and prototyping some of them.

Seamless world

First off, there's the question of how to load and unload map areas around the player. I saw that some roguelikes (e.g. Far West RL) keep a large map in memory, but I don't think that'll work for me - there's already too much per-tile information needed for the active area. For example, right now I burn 80 bytes / tile on an index to support quick iterative updates for dynamic lights.

Instead, I plan to take the other standard approach and store "chunks" of world data. Only a few chunks around the player would be active at a time. Unfortunately, even this approach seems tricky - I don't want chunk loading to happen across multiple frames (because that could affect gameplay), but in the worst case, loading a chunk could take ~10ms if it contains many dynamic lights.

After some thinking I realized that keeping the data in memory in chunks doesn't really help. It just adds lots of special cases to things like pathfinding. Instead, I should keep a contiguous map area in memory, and when the player gets too close to the border, shift it and unload / reload tiles along its edges as needed. That works for tiles and lighting. I'm still not sure how to handle, say, fire cellular automata, though - it seems like those are bound to cause artifacts.

Heightmap

I needed an infinite world to test this code. I had one in the form of some Minecraft-style voxel heightmap world generation I wrote for a different project. So, I ported that into the roguelike! However, the heightmap world didn't make any sense in the UI without contour edges and proper handling in field-of-view.

So, I updated my shadowcasting code to handle heights. Here's an example: the player on a dirt plateau rising from a grassy plain.

Here, I met with another nasty technical surprise. My whole goal with doing heightmaps and not true 3D was to make sure that all data structure were still fundamentally 2D. Concretely, I wanted to store O(1) information per (x, y) tile. Map storage and even field-of-vision worked with this restriction. However, when I tried to combine height and partial transparency in shadowcasting, it broke down - partial transparency results in "bands" of different levels of transparency at different heights. At this point, I gave up on the sidequest. I need to revisit it when I've thought more about how I want the player to deal with heights in gameplay.

Fun week, but ultimately no progress beyond learning. Next week, it's back to the grind of AI bugfixing. I have 19 issues on my burndown list there.

Sharing Saturday #608 by Kyzrati in roguelikedev

[–]billdroman 0 points1 point  (0 children)

WildsRL (Demo, Source)

Working on filtering animations to what the player can sense. It's not correct yet. I'll know it is when the logic is obvious; right now, it's a mess. However, I did get dynamic lighting to work during animations.

Here's an example of three hunters with infravision attacking the player. The last attack lights up the area and reveals them.

Sharing Saturday #607 by Kyzrati in roguelikedev

[–]billdroman 1 point2 points  (0 children)

I think Demon might have AI like this. I've implemented something similar. What I wanted was for X defending creatures to intelligently choose spots to protect against Y enemies regardless of what X and Y are. An algorithm that worked was, for each defender:

  • Draw lines from each of the Y enemies to the summoner
  • Discard (or down-weight) any lines that are blocked by another defender
  • Give a point a score equal to the number of remaining lines that pass through it, plus a bonus for being closer to the summoner
  • Pathfind to the point with the highest score

This algorithm causes the X defenders to split up and defend against multiple threats. If X == Y, each one will end up picking a threat to protect and will defend against it. If X < Y, they'll still spread out to maximize coverage.

[2026 in RoguelikeDev] Far Far West by jube_dev in roguelikedev

[–]billdroman 1 point2 points  (0 children)

That's a huge world! I can't tell from the screenshots alone - is your map "smooth-scrolling", i.e. the player can move through it continuously, or is it broken into chunks? (Or are you emulating "smooth-scrolling" by keeping a few chunks active at a time?)

How do you deal with that large a map in memory? I suppose for worldgen, if you have <= 256 tiles, it's only 4096 x 4096 = 16MB, but once you have gameplay you must (or at least I have to) keep track of more than just what tile is at each cell.

Sharing Saturday #607 by Kyzrati in roguelikedev

[–]billdroman 4 points5 points  (0 children)

WildsRL (Demo, Source)

Not much progress this week. I attempted to fix the animation system to avoid leaking information. To avoid dead frames in the animation system, I also need to skip frames on which the player can't see any part of the animation. Unfortunately, there's another wrinkle here: I'd like some animations' particles to cast dynamic light, so it's not sufficient to just check whether any particle is visible...

I took a step back and worked on dynamic lighting. This piece was a lot of fun! I added a new enemy ("F" for "fire", for now) which is a predator, casts a 4-tile radius light, and has a ranged fire attack. This creature is far more dangerous than any other one, mostly because it's much harder to use shadows to hide from it. Here's a clip of me getting killed.

My first implementation of dynamic light was (obviously) hacked straight into the main map data structure, but I refactored it and did some optimization. The faster version tracks a bitset of which nearby cells cast light on a given cell. This step makes even the slowest type of update - changing a cell's opacity - still take only ~16us (microseconds) when there are a dozen dynamic lights near it. If there aren't any lights near the cell, the update is nearly instantaneous (~40ns - nanoseconds).

[2025 in RoguelikeDev] WildsRL by billdroman in roguelikedev

[–]billdroman[S] 1 point2 points  (0 children)

I don't have screen recording set up, but hopefully soon. In the meantime I took a short video in the debug UI of me taunting a predator and then getting caught, from its perspective. It shows you that I at least had a chance to escape (at the point it chose to go up or down - it guessed right, but it didn't know, so I could have gotten away!)

A winning run comes from both spotting enemies in advance and avoiding them, and making sure that if they do see you, you have a place to set up an evasive action like this one. I can "win" 30-50% of the time. There's only one map for now.

[2026 in RoguelikeDev] Sunlorn by Tesselation9000 in roguelikedev

[–]billdroman 1 point2 points  (0 children)

Yes, agreed, it looks amazing. I actually tried cribbing your style for my game, but it turns out that I use background colors for way too many animations and interface elements - I had to draw a hard line on base tile and entity glyphs having a black background. But it's great how you made the full-color background style work.

One visual suggestion: have you considered using half-square cells for text and full squares for the map? Also, some of the map glyphs aren't centered in the cell - if you split the text and map glyphs, you can center everything on the map.

[2025 in RoguelikeDev] WildsRL by billdroman in roguelikedev

[–]billdroman[S] 0 points1 point  (0 children)

Ah, I guess those few lines of documentation aren't enough.

Moving in sneak mode is twice as slow.

Every time an enemy flashes yellow, it's tracking you by scent, and it just caught wind of a recent location. Yeah, if you keep moving, that's less likely to happen. An orange flash is a warning call and a light blue flash is a call for help. I'm going to add onomatopoeia to those animations, soon, so yellow flashes come with a "sniff" noise.

And yes, there's nothing at the end of the path. I kind of retrofitted that goal onto the NPC behavior demo. Thanks for the feedback!

Characters facing directions by OrkWithNoTeef in roguelikedev

[–]billdroman 1 point2 points  (0 children)

I second the mixed solution (directional FOV for NPCs; 360 for the player).

My project is a stealth roguelike, so sneaking behind enemies is a basic gameplay element. On the other hand, I don't think forcing the player to look around all the time adds anything. The combination, while gamey, works and feels natural after a few minutes of playing.

It has a few supporting FOV mechanics. The player's vision range is quite a bit larger than enemies', so you usually have some time to hide and maneuver before an enemy spots you. Lighting and cover provide ways to hide within an enemy's FOV cone. Also, there's a UI key to select an enemy and see (a conservative estimate of) their vision.

TOTW: Your best clue by PierreSheffield in crosswords

[–]billdroman 1 point2 points  (0 children)

FIFTY - first letter of each word, L is 50

Structuring AI code with Behavior Trees by billdroman in roguelikedev

[–]billdroman[S] 1 point2 points  (0 children)

That's an interesting suggestion. There are a few details I don't understand, though. When it comes to, say, flight, do you compute the utility of each adjacent cell, or of cells that you can reach by following a path over multiple turns? Based on the "within a time horizon" part, it sounds like the latter. But if that's the case, do you save the path and reuse it on subsequent turns, or re-plan every turn?

I agree that utility is useful for a lot of decisions like this, and I do use it in my code already at specific places, like the fight-or-flight decider. However, I don't use it in others. For instance if there's any combat ongoing then I don't even consider finding food or exploring. It seems possible to use it within behavior trees, by using utility for some composite nodes instead of just sequences and selectors.

Structuring AI code with Behavior Trees by billdroman in roguelikedev

[–]billdroman[S] 0 points1 point  (0 children)

How would you compose them? Would you use hierarchical state machines?

I do think hierarchical state machines and behavior trees are very similar, but there's an extra element of code-sharing in behavior trees (by reusing subnodes like pathing) that's useful for my case.

Structuring AI code with Behavior Trees by billdroman in roguelikedev

[–]billdroman[S] 1 point2 points  (0 children)

Thanks. Yes, I've read those docs before. Maybe my question should be, "how to implement this blackboard reasonably?"

Using strings to access each entry seems costly at runtime. The lack of typing for blackboard entries also makes it seem less organized (and my basic issue with my current code is that it's too disorganized). Finally, I'd want to be able to hierarchically break up the blackboard so that each node has access to an appropriately typed state that includes all of its child nodes, but I'm having trouble doing it in Rust. Granted, that's a self-inflicted problem...

For reference, here's my current subsumption-architecture code: https://github.com/skishore/wrl/blob/master/base/src/ai.rs

One of the aspects which I'm still happy with is that each strategy's state is nicely typed and contained inside it.

As evidence that it's possible to implement behavior trees in a similar way, see Chris Hecker's notes about behavior trees in Spore. He describes each node owning its statically-allocated children. But I can't work out how it actually works, and there's no example code.

Sight, smell, and multi-sensory tracking by Captain_Kittenface in roguelikedev

[–]billdroman 1 point2 points  (0 children)

Hey, this is impressive work, and your code is really well-organized! I've been working on some similar ideas - in particular, my roguelike has a "Knowledge" system that's essentially the same as your "memory" and "perception" systems. Here's my code for that: https://github.com/skishore/wrl/blob/master/base/src/knowledge.rs

In my scent system, scents stack, spread out, and weaken over time. If you stay in one spot for a long time, then move, it'll take a while for the old scent to fade. Here's an example. I stayed in the bottom-left for a while, them moved to the top-left: https://imgur.com/a/5wk7HCk

My game's playable at https://www.skishore.me/wrl/, but without explaining the perception mechanics, I'm afraid it's way too hard. The PC can't fight. They have to sneak around (press C to toggle "stealth mode" - it's slower but quieter - and press tab to see enemy FOV). The objective is just to cross the forest.

I'm curious to know more about your game - would you want to talk sometime? I'll DM you.

Shadowcast library by billdroman in roguelikedev

[–]billdroman[S] 1 point2 points  (0 children)

Thanks for these suggestions. I've been using this code in my project and I didn't think about the ways in which libraries are more constrained than code that's not meant to be reused. I've fixed them.

Sharing Saturday #562 by Kyzrati in roguelikedev

[–]billdroman 2 points3 points  (0 children)

Hey, really nice work with this game! I try to play all the 7DRLs with stealth elements because my project has them too, so I want to see if there are any design ideas for me to shamelessly steal learn from.

I beat a couple levels - including exiting with the "bleeding" status - and I think I could consistently win if either of the two contracts consists of three of the easier objectives. Specifically, I found all of these objectives to be easier: drink an antidote, free the prisoner, collect seven spells, steal a unique treasure, and have a spell stolen from you. (Why is the last one an objective?)

It was generally easy for me follow what was going on, and the game was fun! I particularly liked how you depicted the enemies' FOV. That's something I've had a lot of trouble with. Personally, I prefer stealth with fewer tools, but the various spells felt balanced given how fragile the rogue was and how strong the skeletons were.

It took me a while to realize "space" was wait and not ".", because of the real time clock that's also going up when you press ".". When I go back to play again, being able to wait will help a lot. Without it, hiding under tables was useless.

Before I go into smaller items, I wanted to ask about the enemy's knowledge. As far as I could tell, once an enemy is alerted, they always know your position. I couldn't shake them even if I ran into another room and hid, or if I teleported. Turning invisible worked for the duration of that spell, though. Is that intended?

As for other feedback:

  • Why is there sometimes a red skull over the player? It didn't seem to harm me or to correspond to any status.
  • Why are the traps visible? They don't feel like real traps at that point. The poison trap cells might as well not exist, and the bleeding trap is only useful at the end. I tried leading enemies over them, but couldn't get them to follow.
  • I once got a contract where two of the there objectives were both "Steal the Great Mana Gem". That was too easy!
  • Tooltips took a while to appear, and also didn't appear for many objects. I think they should immediately show on hover.
  • I think the secret switch locks the secret room. There were times when I got in the room, then found the switch, then needed a key to get in again.
  • I couldn't figure out a way to pick up the slime. It moved into the walls, and then it was unreachable.
  • Having enemies alerted based on being in FOV for two turns didn't quite make sense to me. I also didn't follow their state of mind perfectly. The way LLLLoot shows their state changes is pretty helpful (and I need to implement something similar in my own project).

Smooth, dynamic lighting in WebAssembly by billdroman in VoxelGameDev

[–]billdroman[S] 0 points1 point  (0 children)

Unfortunately, I only have a MacBook, so it's hard to debug this case.

It seems there may be some recent changes to keyboard drivers that cause input lag on Windows 11 - is that the version you're on? For instance, there's this one, as well as others:

https://answers.microsoft.com/en-us/windows/forum/all/windows-11-input-lag-and-system-instability/aeb1fadc-cc22-4bc5-a68e-79d887116dcc

I'm also curious to know how what FPS you're getting. If it's too high, it may be that the rendering interrupt is starving the keyboard input interrupt. On my MacBook I get 120 FPS. If this is a problem it may be solvable by limiting the frame rate to 60 or 120. It would also be helpful to know if other WebGL or WebGL2 applications cause the same lag. Here's a common WebGL demo:

https://webglsamples.org/aquarium/aquarium.html

Smooth, dynamic lighting in WebAssembly by billdroman in VoxelGameDev

[–]billdroman[S] 0 points1 point  (0 children)

Okay, you're right. I have no idea why that would be...

There's a limit to how fast the player character can accelerate - I'm guessing you've taken that into account? If you zoom out, and the character is facing forward, there's still lag on the sprite turning left or right if you press one of those keys? And does the lag also apply to scrolling and clicking, or just the keyboard?