Two devlogs ago I promised you a fishing rod and gave you an apology instead. One devlog ago I built the pockets you'd need to keep anything you caught. This is the entry where the promise finally comes due. Stand at the edge of one of those black underground pools, press F, and for the first time the game doesn't apologise. Your line goes into the water. Something down there is already moving.
What there is to play
Press F beside water and the dungeon quietly steps aside for a small panel: the pool, seen edge-on, seven rows deep. Somewhere in it, fish are drifting — a t for a trout up in the shallows, a c for a carp in the middling dark, a s for a salmon deeper still, each keeping to the depths it likes and wandering left and right as it pleases.
You have two controls that matter. Left and right swing your rod, sliding the hook across the water. Up and down pay the line out shallow or deep. The whole game of it is patience: read where a fish is heading, put your hook in its path at the right depth, and wait. Line one up and it takes the hook — the panel breaks into an alarm, and you have a heartbeat, four turns and no more, to strike with Enter before it spits the hook and is gone.
Strike in time and the fight begins. You reel with Up, and the fish fights back — now and then it runs, tearing line back off your reel, so a landing meter that was nearly full can suddenly slip. Out-last it and it's yours: into the pack it goes. And because of the unglamorous plumbing from last time, the story doesn't end at the water. Press E and you can eat what you caught — a fish is the best meal in the dungeon, and out here, with your belly ticking down every step, that is no small thing.
Where this actually came from
Here's the surprising part, the strange direction I hinted at last time. The fishing didn't come from the roguelike at all. It came from another game of mine — one still back in the workshop, written in C++ and SDL3, that trades dungeons for deep space and, of all the unlikely things, is partly about casting a line where you would least expect to find water. I'm not going to name it yet. But it's real, it's being built, and I'll have a good deal more to say about it later this year.
What I did here was reach into that project, lift out the fishing whole, and translate it into the browser. And the reason I'm telling you — the reason it's worth an entry rather than a footnote — is how little the translation cost, and why.
Why it ported almost mechanically
I braced for a fight. Moving a mechanic from C++ and SDL into JavaScript and a web page sounds like the kind of job that eats a weekend and half your patience. It didn't. It was nearly a transcription. And the reason is the single most useful thing in this whole devlog, so let me say it plainly:
The fishing has no timers, no physics, no frames. It is nothing but whole numbers on a grid, changing one turn at a time. And code shaped like that will travel to almost any language you like.
Think about what usually makes a mechanic hard to move house. It's the frame-rate-dependent bits — the smooth motion, the floating-point physics, the this-many-pixels-per-second that assumes a particular engine and a particular clock. The fishing has none of that. A fish is at column 11, row 4. A hook is at column 12, row 4. Are they close enough to bite? That's a comparison of integers, and an integer means exactly the same thing in C++ as it does in JavaScript. The mechanic is a little state machine — waiting for a bite, then a bite you must answer, then the winding fight — and it takes exactly one discrete step each time you press a key, which is precisely how the dungeon above it already worked. The two halves of the game keep the same heartbeat. That's not luck; it's the whole reason turn-based, integer-state design is worth loving. It's portable almost for free.
It's the same lesson the glyph atlas taught me back in devlog 01, wearing different clothes: the decisions that come from decades of C++ don't stop being true because the language changed. Turn-based logic is turn-based logic in any tongue.
Who did what, and the bug worth confessing
My part was the feel of it. That fish should drift rather than sit; that a bite should have to be earned by reading depth, not handed over for waiting; that the fight should sometimes take line back from you, so that landing a big one feels like winning an argument. The numbers behind all that — how often a fish runs, how many reels it takes to land, how the rare ones lurk deepest — those are mine, tuned by playing it until it felt right.
And there was a lovely, instructive bug. Two different bits of the code each worked out which column the hook was in — one to decide whether a fish was biting, the other to actually draw the hook on screen. They disagreed by a column. So fish would "bite" in a spot where you could plainly see no hook at all: maddening, and completely invisible until you stared at it. The fix is a rule I should have followed from the start and now follow everywhere: work a thing out in one place and have everyone ask that one place. One function decides where the hook is. The sim and the picture both call it. They cannot disagree, because there's no longer two of them to disagree.
Something that shouldn't be down there
One last thing, and then I'll let you go and fish. Keep your line deep, and be patient, and very occasionally you'll pull up something the guidebook has no name for — something that has no business swimming in a dungeon pool, or perhaps anywhere. I've said too much already. Fish the deep water and see for yourself.
No roadmap, as ever. The door that leads to space is still just a rumour between me and the machine. But the water works now, and there's a fish frying, and a month ago there was neither. Go on — F, and mind the deep.
Want the longer, patient version of these ideas, hand-written in C++? It's in Roguelikes in C++ with SDL3 and the free Learning C++ by Building Games.