~/adam.log

Custom Roguelike - The Demo Ships and the Story Begins

Published 2026-11-08

The Demo Ships and the Story Begins

The store page catches up with the deck builder

With the cards in, the Steam page was describing a game that no longer existed. I went through the whole thing again: the short description now opens with “A deck-building roguelike”, About This Game talks about hands, card offers and making your best cards permanent, and the tags and all six Early Access answers got the same pass. The base page took the new text the same day, and the demo got the same copy once its review cleared.

A shot list for the trailer

Steam won’t review the full game’s build without a trailer, so I wrote one out shot by shot before recording anything. The structure I settled on: the title, then Build your deck, the five area attacks, Bosses that fight back, the five Decks, and the Final Demon, with all five classes walking side by side in five panels as the transitions between sections. Every take got a number and the exact battle tester command to set it up, so a recording session is just working down the list.

I also turned my old Windows sound test folder into a clip builder: the game and the battle tester built from the same commit, so every clip in the trailer comes from one build. The battle tester lost its banner over a floor and the enemy gallery too, since it kept ending up in the shots.

Recording, take one: no sound

The first full session covered most of the list, and every one of the five audio tracks was completely silent. After the audio driver reinstall the week before, OBS had lost its desktop audio device. The first cut went together anyway, with sound effects laid in by hand on the big beats, but it was clear the trailer needed a re-record.

Recording, take two, and the trailer

The second session went down the whole list in one 20-minute recording, this time with the game’s sound on its own track. I can’t scrub through 20 minutes of video by hand for every cut, so the moments were found from still frames: contact sheets every two seconds, then every half second around each attack, kill and card pick. For the walking shots, measuring which way the map scrolled between frames found every left, right, north and south walk without looking at them at all.

Three rounds of cuts later the trailer is:

  • The title, then Class Select scrolling through all five heroes
  • Build your deck: three card offers and a “Make a card permanent” pick
  • Attack your enemies: Whirlwind, Blizzard, Flurry, Javelin Volley and Arrow Volley, each labeled with its class
  • Bosses that fight back: the Ettin Overlord swinging back, the Houndmaster whistling up his dog, the Skeleton King raising a skeleton, the Bullywug King’s gas cloud and the Yeti King calling a cub
  • Your deck, your build: a second on each class’s Deck
  • Go five Blades deep: the Final Demon lunging, then a cut to black and the end card

The first versions had the bosses dying instead of fighting, so I swapped those for their attacks. The music starts almost silent under the title and Class Select and builds to full as the first Whirlwind lands, with the game’s own sound effects underneath. One gotcha: the final loudness pass was quietly lifting the soft opening back up, so the whole mix now gets one fixed gain instead.

The demo is out, three weeks early

The demo was planned for November 16, but Valve passed its review today, so I released it today. The approved build was from before the deck builder, though, so first came a new demo build from master. I uploaded it to a private test branch, played it to check the cards were there and achievements fired, then set it live and pressed the button.

The same afternoon the store page got its ten new screenshots, all from the new recording, and the trailer, with the title card as its thumbnail. The end card now says “Play the free demo” instead of the old date.

Small things found along the way

  • “The Demon Flees!” box sat on top of my health and ATB bars. It was placed by its top row, but it grows with the text size setting, so at a bigger text size it ran down into the bars. It’s now placed by its bottom edge, a row above the bars.
  • Two new items on the todo: the Sewer uses its water-channel battle backdrop for every corridor fight, when it should only be beside the water, and the small cards in the battle hand look soft and need redoing.
  • Boxes drawn over each other. The first friend to play the demo sent screenshots of boxes fighting: the mini map’s frame across the speaker’s portrait in the prologue, another box’s frame through the Tutorial text, and the “Achievement unlocked!” pop-up printing over the Blacksmith’s talk box. Every box was drawn on the same few layers, so whichever drew last won. Pop-ups now get layers of their own above the HUD and the mini map, and the achievement toast one above that.
  • The Demon’s lost hand. The prologue’s fights deal scripted hands, and the Demon fight’s second one never showed up: the game took it off the script the moment the first card was played, before the hand was empty, so it was thrown away and a random hand dealt in its place. That’s in the released demo too, so it’s the first fix for a demo patch.
  • The potion line nobody read. In the prologue, the line telling you to walk over the potion appears while you’re already walking south toward it, and it closed on your next step, so it was gone before anyone could read it. It’s now a box you close with Enter, like the rest of the story.

The Sewer’s backdrops

Every corridor fight in the Sewer used the backdrop with the water channel running down it, even in tunnels nowhere near water. Now the water tunnel only shows when the fight starts right beside the water or by a bridge. A room with water in it, and the dead end of a tunnel, get the dripping pipe, and every dry tunnel and room gets the pipes. Over twenty test floors, the water tunnel went from every corridor square to about one in six.

The small cards

The small card that sits beside the Actions box while you pick an enemy had red flecks all through its text, and on the lava floors it looked broken. The cause turned out to be one line in the graphics library’s shader: any pixel close enough to black is drawn as see-through, so pure black can be used for empty space. The small cards are made by shrinking the big ones, and the shrink leaves a faint dark ring around every letter, just dark enough to cross that line, so the battle background showed through the text. The card tool now nudges anything that dark up a shade before saving the sheets, a change too small to see, and the letters are solid again.

Demo feedback: the quick fixes

My friend’s notes on the demo had a handful of small things, and they’re all in now. Discard hand used to throw the cards away on the first press and then wait for a second one, which read like a bug; now the first press dims the hand where it is and asks “Discard 3 cards? Your gauge starts 0% full.”, with Enter to go ahead and Esc to keep them. The victory screen no longer says “the Hellhound, the Hellhound, the Hellhound, and the Hellhound”: it’s “four Hellhounds” now, with real plurals for the Snow Wolves and Guard Women and the Lizardfolk left alone. In the prologue, the fights where only one card can be played now always show a small Tutorial box saying which card to pick, so the grayed-out ones don’t look broken. My buff icons moved out of the way of my own axe: they used to stand in a column right of the hero, right where the attack swings through, and now they’re a row just above the ATB bar. And the Heal card, which read like it raised max HP, is now “Instant Heal”, “Restores 40% of max HP”, with a red cross on it instead of a potion, so it no longer looks like something you keep.

More chances at a gold card

The same friend killed a boss with every ability card they had and then got no “Make a card permanent” choice at all: it only offered cards you were still carrying, and the one-use cards you’d played were gone. Now it always offers two random cards from the class’s whole pool, rolled with the floor’s rarity odds, skipping any you already hold in gold. If you have the card, a copy turns gold; if not, a gold copy joins your deck. Gold map cards also stopped being used up: Roar and Ice Armor work any time, Stealth and the Invisible Cloak come back after five won battles, and the ranged attacks and traps after eight. While one recharges, the Ability Bar grays it out with the battles left.

One hand on the keyboard

My friend also asked for a Confirm key, so the game could be played with one hand on WASD. That grew into rebinding everything the game asks you to press: Confirm, Back, Wait and the Mini Map join the moves, the Item Menu and Give Up Quest in the Hotkeys list. A bound letter simply acts as Enter, Esc, Space or Tab would, and the real keys always keep working, so nobody can lock themselves out. The text follows along too: if Confirm is E, the boxes say “Press E to continue.” instead of naming Enter. The old R shortcut for resetting the keys is now a proper “Reset to defaults” row.

The mouse

Another thing my friend asked for was the mouse, and now the menus and the battles take it. Every screen marks what it draws that can be clicked, and the next frame checks where the pointer is: hovering moves the cursor, a click picks, the wheel scrolls and a right-click backs out. In a fight you can click an action or a card in your hand, then click the enemy you want to hit. The Options screen got the most out of it: the video and gameplay settings now drop down a little list of their values to choose from, with the change showing live while you look, and the volume bars set to wherever you click. Walking around the map still belongs to the keyboard for now.

The Bestiary

The last thing on my friend’s list was a bestiary, and it replaces the old “Enemies defeated” page in History. Each theme gets a page: its enemies down the left, bosses at the bottom, and the one you pick shown on a card with its sprite moving. An enemy you’ve never met is a black silhouette and a row of question marks. Once you’ve fought it you see its art and name, and every kill teaches you more, measured against that enemy’s kill achievement: the first kill shows its HP, a third of the way there its damage, two thirds its speed, and when you earn the achievement it’s Mastered and the card adds its moves and a line or two of lore. All 52 of those lines got drafted and signed off in one sitting. The demo shows the Sewer’s page and keeps the rest for Early Access.

Tougher bosses

The bosses were going down too fast: about three or four of my turns on the first floor, and not much more on the last. Every tier’s bosses got 15% more health, the Final Demon too, and a boss that fights alone, with no escort, pack or summons, gets another 20% on top, since nothing else stands between it and me. The bots now keep count of how many turns every boss takes to kill. After the change the fights run about three to five turns on floor 1, five or six on floor 2 and seven to nine on floor 3, close to what I’m aiming for. The win rates barely moved, though 5 Blades slipped a little, and the Final Demon still wins more fights than it loses.

Mac and Linux

Another request from the demo was a Mac or Linux version, and both are built now. GitHub builds them for me, since I don’t own either: the Mac one as a proper app that runs on both Intel and Apple’s own chips, and the Linux one on an older Ubuntu, so it isn’t too new for players’ machines. Steam achievements work there too: the game now loads Steam’s Linux or Mac library from beside itself, the same way the Windows version does. I set up a Linux and a macOS depot for the demo, and the first upload put all three versions on a private test branch for friends with a Mac or a Linux PC to try. I could run the Linux one myself in WSL, but not through Steam. Until they’ve tested it, the public demo got a Windows-only build of the same code, which makes it the demo’s first update: the mouse, the rebindable keys, the Bestiary and the tougher bosses. From now on every update that goes live on Steam also gets an announcement on the store page, so the game has a dev log there too.

A longer Vanish

The Rogue’s Vanish, the smoke bomb that hides you without leaving the fight, only ever dodged one attack: in a fight with three or four enemies the next one found you straight away, so it was barely worth the card. Now no enemy can hit you until you act again. Any action ends it, the ambush strike that follows included, so you can’t hide behind it forever while drinking potions. The bots now count it as dodging a hit from every enemy in the fight, and a Rogue-only run came out about the same as before, 56 wins in 90 against 61, which is within the noise.

The Elder’s gift

The bots kept losing 5 Blades to the Final Demon, and every class the same way: almost every death in that tier was the Demon. So I taught them to note their health and potions as each boss fight starts, and that showed where it goes wrong. They walk into the first Demon fight at full health, but every time a Blade goes in he flees to another plateau, and the chase through his guards drinks every potion they have. The fight that decides the run starts at about half health with nothing left. Now, on the last town visit before his floor, the Elder waits at the gate with a gift: two Healing Potions, all the town could spare. I tried one, two and three, and three with a harder-hitting Demon; two came closest to what I want, the tier going from 35% to 45% wins. The Barbarian still reaches that last fight weaker than anyone, which I want to look at next.

Iron Hide for the Barbarian

The Barbarian walks into the last Final Demon fight weaker than anyone, at a sixth to a third of his health when the others have about half. Nobody in the game can heal, and I want to keep it that way for now, so I looked at how he loses health instead. The bots now log how much every class loses per fight and to what, and for the Barbarian about half of it is his own Reckless Swing hitting him back. I tried four fixes, a bot run after each: a smaller recoil, Rage lasting from one fight into the next, and a new ability, Iron Hide, first as less damage for a while and then as extra armor for a number of hits. Only the smaller recoil really mattered, and the armor at +4 made him win every single run, far too strong. So Reckless Swing and Rage are back as they were, and the Barbarian starts with Iron Hide: used on the map, +2 armor for the next 20 hits he takes, wearing off a hit at a time. It can turn up in the card offers too. It has its own icon, two iron fists in a red glow, and its own red aura when he uses it.

Hunter’s Mark and the dodges

Two smaller visual pieces. The Hunter’s Mark got a new crosshair, drawn by hand rather than generated, a smaller one over the enemy and a bigger one as the card’s icon, and the marked enemy now flashes yellow as it lands so you can see who it went on. And every hero now has a dodge: when an attack misses, because of Evasion, Vanish or a blinded enemy, they lean or hop out of the way instead of just standing there. The Mage also got a new hurt animation, doubling over from a punch to the gut.

Testing the gold recharges

The gold map cards that come back after a few battles had numbers I’d picked by feel, five battles for Stealth and the Invisible Cloak, eight for the ranged attacks and traps, so I let the bots play every class through every tier with them. A couple of things got tidied first: Iron Hide joined Roar and Ice Armor as a gold card you can use any time, and a plain copy of a card is now playable while its gold copy recharges. The win rates came out 68, 47, 69, 55, 47 and 40% from the Crawl to 5 Blades, a few points under the last full run in most tiers but inside the noise everywhere, and the Barbarian, now with Iron Hide, won exactly as often as before. So the numbers stay.

The Elder at the gate, seen

I finally saw the Elder waiting at the gate on the last 5 Blades visit, and he looks right. One small thing: after he hands over the potions, his talk box sat across the top of the screen, right over the dungeon entrance. Now, once the gift is given, his box moves down to the bottom of the screen.

The Final Demon, tightened

A handful of changes to the last fight. Every Blade you stab into the Final Demon now makes him a bit tougher: 15% more health each time he comes back. In exchange, when he flees he only runs to a plateau one bridge away, so the chase through his guards is shorter. None of his fights hand out card offers any more, since the run ends with him and a new card that late meant nothing. On the ending scene the hero stood a head taller than the townsfolk around them, so they’re drawn a little smaller there now. And the Bestiary had been showing the Hound Master in his place; it shows the Demon now.

Driving the Blades in

I rewrote the Elder’s lines at the gate, and while I was at it went looking for every place the story said the Blades had to be “spent”. It never sat right: spent on what? The idea is simpler than that. The Blades hold the Demon to this world, so he keeps coming back as long as they’re in it, and the only way to end him is to give them up by driving them into him and leaving them there. The Bestiary, the send-off on the last visit, the Witch and the Elder at the end of the prologue all say that now. The Elder’s last prologue line waits for a hero “willing to drive them into the Demon and strong enough to let them go”. And the Blacksmith stopped asking for a Warlord’s axe: there was never one to bring him, and the Orc Warlord fights with two swords anyway.

Tidying before Endless

Endless is coming with the full game, and before it does I want the code ready for it. First step: the game’s main state had grown to about seventy-five loose fields, with what the current run has done, where every menu’s cursor sits and how the ending screens are animating all mixed together. Now they live in three groups: the run, the menus and the end screens. Nothing plays any differently, but when Endless needs a run that keeps going, the run’s state is one thing in one place. Second: “is this the last dungeon?” and “is this the last floor?” were asked in a dozen places, each its own way. Now the tier answers them itself, so Endless only has to give its own answer in one spot. Third: the battle tester, my tool for trying out maps, enemies and classes, had grown into one 2,600-line file; it is now five smaller ones, each doing one job. Last: the two longest functions in the game, the one that handles an enemy dying and the one that decides each step for my test bots, were each a few hundred lines long. They now work out what they need first and hand it to a handful of smaller steps.

The Battle Bar steps aside

The Battle Bar is Off by default now. New players see the Item and Ability Bars centered together, with less on screen while they learn the cards; anyone who wants it back turns it on in Options > Gameplay.

The whole story in one place

With the full game waiting on Valve’s review, I turned to the story. Bits of it lived in the town script, the prologue, the Bestiary and my own notes, and some of them disagreed. So I wrote it all down in one document, start to end: the wizard who called the Blades up out of the nether and was pulled in for it, the Demon who came through with them, the hero of the prologue, the Blades scattered across the five places, the five heroes of the main game, the ending and Endless. Wherever nothing had been decided it says so instead of making something up, and wherever the game already contradicted itself it’s marked, so I could settle each one.

The summoning

The first piece of that story to make it into the game is a cutscene. It needed a cutscene player first: scenes, characters walking a path, talk boxes with a face, sounds and music, all scripted, plus a mode in my battle tester to play any of them. The summoning opens outside the wizard’s mansion at night, in the middle of a forest, then looks down through the roof into his lab on the top floor. He has gone to all five places searching for power, and he lays one thing from each on his altar as the price. The circle turns crimson, the Blades rise out of it, and as he steps up and touches them the nether flares and takes him instead. Out of the flare comes the Demon, who walks down the stairs and out toward the castle in the hills, leaving the Blades where they lie. The wizard and the visitors got their own talking faces, there are six new sounds and a birds layer outside, and three new pieces of music: the summoning, a sting for the Demon’s arrival and the mansion at night. It plays when you beat the Skeleton King, as his battle’s win screen closes and before the run’s own win screen, and Esc asks whether you want to skip it.

Finding the Blades

A second cutscene is made too: years later, by day, a few sellswords shipping out find the empty lab, argue over the Blades and take them, two, one and two, to the places the main game finds them. It’s done and I like it, but it belongs to the Mountain, so it waits until the Mountain has its lore. Along the way the Blades themselves got redrawn: five upright steel Blades with gold hilts, and the ones on the prologue’s floor are the same ones now.

The prologue, rewritten

The prologue’s hero used to come across as vain, shouting “I won!” over the Demon’s body. That’s not who he is. He’s a real hero, out to save the town, who gathered the Blades one at a time just like the player will, and they are already working on him: he hears things and he’s starting to slip. The Elder begged him to give them up and he wouldn’t, because the Demon always comes back and someone has to hold them. In the end he lets all their power in to beat the Demon, more than a man can hold, and it burns him out. So I went through every line of it again, room by room, and the castle got a new map to go with them: no corridors, every room dressed, the great door in sight from the ambush when he says he can feel the Demon behind it, and the castle’s outside at night, with a dead forest and a cliff road. The Demon’s curse is gone; in his place, from the first thing the hero does in the last fight, the Blades burn him a little each turn, with a hum under it. The Blades even talk now, after a fashion: a still face, “…”, and that hum. At the end the Elder sends each acolyte off by name, one Blade each, in the order the runs take them.

Lore in the Sewer

The main game hints at the story rather than telling it, and the first hints are in the Sewer: five lore pieces, the wizard’s own journal pages and the things he left on his way through, plus a note from the acolyte who hid the Sewer’s Blade. Each sits in a room dressed for it, a scorched page by a giant rat’s bones, a page in a broken floor tile by a cold camp fire, scratches on a wall, a throne of rubble, and you read it by walking into its glint. A piece once found stays found from run to run, its box shows the piece’s own icon, and the first one you find tells you where to look them up.

History and the Lore page

That place is History. Its menu now shows Classes, the Bestiary and Lore, each with a line under it saying how far along you are. The Lore page lists every piece by place, “???” until you’ve found it, with its text on a card beside the list, and each place’s cutscenes under its pieces: the summoning can be watched again from there. The Arena and Endless are hidden from History until those modes ship, and the Items page is off the menu for now.

Small things before the next build

The Dungeon Crawl’s opening text now matches the new prologue. In the Sewer, any square next to the water gets the water tunnel backdrop, rooms and dead ends too, not just corridors. A boss’s body stays where it fell while the rest of the fight goes on. After Discard hand the cursor jumps to the new hand’s first card. The Red Slime goes from 18 to 26 health, since it was dying to a single hit on the Sewer’s second floor. And the fight that kills a run’s last boss no longer offers a new card or shows a loot line, since the run ends right there.