TWELVE DISMAYS OF CHRISTMAS
These aren’t all struggles with the engine. Most of them are struggles with the sunken-footed helioporaceac structure of the codebase (which inherits directly from Cultist, which means there are parts of it that were written in 2016). Or with my own tendency to be distracted and the three-plus jobs I have in a microstudio (I feel the four years it took between full game releases as a personal stain on my honour, but Lottie sometimes reminds me that besides the eventful nature of some of those years, there are two novels worth of text in BoH as well as the actual game). And I can’t emphasise enough how domestic our set-up is on days we’re not in the office. Very likely at least one of these bugs was caused by my kid needing emergency purchases for art homework, or the cats thinking they deserve a second lunch. ANYWAY. Welcome, all ye merry souls, to the TWELVE DISMAYS OF CHRISTMAS.
TWELVE FLYING SCROLLS
I wish I’d thought to take a video of this one, but thanks to M.D. we have this screenshot, lest we forget:
Sometimes when a scroll tried to return to a shelf – perhaps because you’d just read it and clicked Collect – it would decide there wasn’t enough room for it and go somewhere else. If it decided there wasn’t enough room in Shelf B, it would whizz back to Shelf A, but unless you’d opened up some room for it, it would then whizz back to Shelf B again, like a ping-pong ball or a small child darting between alternative cupcakes. It would keep going, as long as you like, dawn and dusk, summer and winter, until you opened up space for it.
Why? A muddle about what size the scroll thought it was, and the methods it used in different circumstances to ask the shelf whether it fit.
I keep a trove of user-provided saves of a heavily populated late-game library, so I can test with real data (and confirm that even very old saves still work. One of these saves is still called CURSE OF THE FLYING SCRO2. Thanks, K.P.
ELEVEN RADIANT WINDOWS
Occasionally I get a fusillade of dismayed bug reports saying ‘everything in the game is just white!’ This screenshot courtesy P.V:
The Glory? Winter? a ferocious freezing fog?
A promo for the first content expansion, whose name when revealed will make this look clever?
BOOK OF HOURS uses a great many 2D images. When a machine has to keep loading them individually into memory, the performance impact can add up quickly. So we use a ‘sprite atlas’, one big giant image with lots of smaller ones fitted together jigsaw style, that the machine can load all at once and keep in memory. Occasionally this big image gets borked, and none of the images can be loaded. Sometimes this is a download hiccup and the user can fix it by verifying the download, but Unity also sometimes chokes when I’m building the binaries for the game, specifically for some reason the Mac binaries. A few times I’ve missed this and uploaded a bad Mac build.
(You might wonder why the card images aren’t borked. We don’t keep them in the sprite atlas, because the narrative content system wants to be able to request images on the fly with names based on json. As with a hundred other things, there’s probably a hundred slightly more performant ways to do that, but the entire tech staff of Weather Factory is half of me plus some freelancers sometimes.)
Incidentally the atlas takes a few moments to load, and if it hasn’t loaded by the time we get to the main game screen, you get the white effect again. The quickest way to fix this was to reference the sprite atlas from the quote screen so it starts loading then, and the first small image in the sprite atlas that came to hand was a potted fern from the Violet Chamber, so every time you fire up the game, there’s an invisible plant just under the first quote.
TEN TINY PUGLINGS
The oldies are the goodies. When we launched the demo in February 2023, there were inexplicable tiny pugs scattered round the Atlantic Ocean and the Cornish moors, among other places, because they were half-finished default images for workstations that I thought were invisible and weren’t, and I’d “cleverly” used a very silly default image so that I “definitely” couldn’t miss ’em.
I did promise to add a PUG OPTION to the menu if we passed a certain wishlist threshold before launch. We did, so that’s still on my task list. Watch the seas.
NINE CRANIAL TCHOTCHKES
This is the Cranial Tchotchke:
It has the distinction of being the oldest non-book item in the game, because when Lottie was thinking about what other things an occult library might have on its shelves besides books, obviously ‘polished former Librarian frens’ came first to mind, so I had art handy for it when I was prototyping.
This is its close friend, the Glinting Cranial Tchotchke, which contains a small secret revealed by close examination:
But this is what it looked like briefly at the end of August – thanks L.M. for this screenie:
This is the effect you get if an image is missing, but I checked and the image wasn’t missing – it had been there from the beginning – so I didn’t realise right away what the actual problem was. A follow-up report and screenie from P.V. was the clue for an instant House-style diagnostic epiphany – you could now hang the thing on the wall like a painting:
There are more than six hundred items in Hush House – not counting books! – so I use a spreadsheet to track their associated text and properties, and output it automatically to the .json files that the game uses to store content. (In the days of Cultist Simulator, I did this manually, which is why I try very hard to avoid doing it manually ever since.)
If that last column is blank, the spreadsheet knows to assume the item is a generic ‘thing’. I’d somehow let ‘wallart’ leak into the cell for the Glinting Cranial Tchotchke when I was jiggling things. Not only did this mean you could hang it on the wall, but it meant the game looked in a folder called ‘wallart’ for the image instead of a folder called ‘things’.
You can no longer hang people on the wall in Hush House.
EIGHT MAGIC CHAIR LEGS
You can Consider anything in the House that isn’t nailed down. Often it yields a Memory, sometimes it yields something else tucked down the seat cushions. Occasionally it got more exotic. Bug reporter J.D. during the beta in July 2023:
“I took a lamp from the Reading Room and put it into coNsider with Mettle and when the recipe finished I had a Melodic Chair.”
I checked, and he was right. If you looked too closely at the lamp, it turned into a chair.
Again, this was just a bit of spreadsheet borkage. The Lumpy Melodic Chair, when examined, yielded a treasure and turned into the Melodic Chair. I’d just put the Melodic Chair in the wrong row and instead created the world’s first developmentally metamorphic reading lamp.
SEVEN CREEPY MOMMETS
The enthusiasm generated by this bug has been rivalled only by the PUG REPORTS incident. Time to reveal the truth.
This dapper gent is the first Baron Dewulf, and his bust traditionally lives in a slot on a little table at the bottom of the Grand Ascent.
However, after an innocuous update at the end of November, some players noticed that the slot where Hendrik could be placed had disappeared; in fact, if Hendrik was in there at the time, he had disappeared too:
After another update, Hendrik returned. But he’d brought a friend back with him.
In fact to the mounting alarm of the affected players, wherever he’d gone, he’d clearly been a hit with the locals, and he’d brought a whole fan club back with him (thanks A.H. for the screenshot):
The clue is in the timing of the updates, which both occurred around the beginning of December, when we unleashed our advent calendar,and when Christmas decorations appeared in the Grand Ascent among other places:
I haven’t been able to piece together the precise sequence of events. but it went something like this:
- In mid-November I prototyped the code that puts Christmas stuff in the game, and then immediately went on a week-long writing break to do the initial planning for the first BOOK OF HOURS expansion.
- I wanted to make sure we had the Christmas stuff live the week before December to work out any remaining kinks ahead of time, so it was a bit of a hustle when I got back, and Lottie and I had some merge problems getting the art into Unity. I’d been testing the Advent code on Hendrik’s niche, and I let the test settings leak into the live version, so Hendrik’s niche became invisible when it wasn’t December. And it wasn’t, at that point, December.
- I almost immediately did another update to fix another issue, and this update (without me even realising it) removed the test settings which had made Hendrik invisible. Unfortunately this code had been live for I think 48 hours, it had made the niche invisible in a number of saves during that time, and now the test setting was gone, there was nothing to make him visible again.
- When people reported the Hendrik-still-invisible issue, I got another fix up which made Hendrik’s niche visible in all times and places. All fine, I thought.
- Not quite. The test settings had used some of the code which puts things on Timothy’s Christmas tree on specific days. So while the bust niche was invisible for 48 hours, it had also been calling some code which invisibly populated it during that time.
- Worse – all this ran into something which wasn’t just a test setting left over, it was an actual bug. The game normally populates a room according to the spec when the room is first opened, and I had to work round that to make Advent presents appear in existing saves (Brancrug Village counts as ‘a room’). The first version of the code, when I was testing, made an Advent present appear every time the game was loaded. I’d already spotted and fixed the bug by the time people reported Hendrik’s disappearance, but meanwhile the bug was quietly doing its thing in the game, and when his niche reappeared, it contained one doll for every time the game had been loaded until the bug was fixed.
- So what happened in non-technical terms was this. Because of an error in a summoning technique I’d been practising, the bust disappeared behind the veil of reality. It remained there until I found out that I’d accidentally created a haunting, and used a counter-invocation to bring him back to the world. Unfortunately, a side effect of the spell was to conjure creepy dolls while he was elsewhere, and because the spell was operating without any oversight or intervention, we got a Sorcerer’s Apprentice scenario. I hope that clears everything up.
SIX DAFFY BANCROFTS
Much simpler one. A.K. (no relation) reported just after the game launched:
“Lord Franklin Bancroft seems to have written his diaries in Latin, a language he seems to be unable to understand.”
There are a couple of dozen visitors in the game, another dozen aspects they might be interested in, and another dozen-plus languages they might speak. So early on I put together a list of who cared about what and what they could care about it in.
You might notice some discrepancies with the information in the game. That’s because this is an old spreadsheet from an earlier phase of design, and I hadn’t set up the automated outputs back then, I just manually typed it into the content files. Later, I considered linking it all up, but the information was in the game already, the sheet was already outdated, it was too much hassle, and the languages they spoke wouldn’t change, right?
When I put together that sheet, it seemed interesting to say that Douglas, being just a copper who’d come up through the ranks, didn’t speak any of these fancy languages. But when I started testing the visitor system, it was inconsistent and mildly annoying that he couldn’t read so many books. So I thought, well, he’s permanently with the Suppression Bureau now, he must have had a decent education; and I got a decent gag about his school scholarship into the game. It’s always fun when character backgrounds expand organically like this.
Unfortunately because my design spreadsheet and actual files were out of date, I just moved around the languages carelessly – I think I had some notional rationale why Franklin spoke Greek but not Latin – and ruined the original cross-checking I’d done against the book list.
For the expansion – and for Game Three – I’m being a lot stricter about connecting everything up round the back. That causes problems too, though, as you’ll see in a moment.
FIVE! LOST! THINGS!
Hahaha wow I had a hell of a time with this one. It went through a couple of different similar iterations while I tried to track it down.
For a little while in September, you could make an object disappear by doing this:
- Pick up an object from Room A on one side of the House.
- While holding the object, pan (technically ‘truck’ as systemchalk would point out, though he’d be very Canadian about it and wouldn’t want to make a fuss) at least a screen’s width to the other side of the house. Yup, your screen’s width, not anyone else’s.
- Drop the object in Room B. Watch it immediately disappear!
- Zoom out in panic and see it reappear.
Here’s what this was.
BOOK OF HOURS had some performance troubles at launch. Like most performance troubles, these had many causes, but one of the most significant causes was that, initially, we were rendering lots of hi-res 2D art all the time. Now we only render a lot of the art when you can actually see it on-screen – this is ‘culling’, it’s pretty standard, but unfortunately for boring technical reasons we couldn’t use some of the out-of-the-box approaches Unity provides to implement this. So there’s custom code that tells the game not to bother rendering rooms, or their contents, when you’re not looking at them.
The key phrase here is ‘their contents’. When is something no longer ‘in a room’? When you pick it up? Or when you drop it in another room? Both of those are reasonable natural assumptions, and different bits of the code made those assumptions slightly differently. So as far as one bit of the code was concerned, when you were dragging a vase from Room A, it was still provisionally in Room A, but another bit of the code assumed that it had already left Room A. So if Room A was no longer on screen, because you’d just moved your camera across the house and it had slid off the left-hand edge, then we should cull Room A, and not waste resources displaying the room or the vases which were probably still in there, right? And because the game updated its records when you did a bunch of other things, it only got out of sync in this one specific situation, so it went mostly unnoticed most of the time. And ‘mostly unnoticed most of the time’ is the helliest smell of bugs.
FOUR MISSING SLOTS
This is the nerdiest example in the whole list, so if the last one made you tune out, wait until the next one to tune back in. But people have been very curious about this one. So if you get excited about spreadsheet formulae and naming conventions, stay with me.
Just a couple of weeks ago, all books in the game written in Deep Mandaic became unreadable. Generally to read a book written in one of the nine great languages, you have to provide a Language card, and no Language slot was showing up for these books. Wut?
Every card in the game has an id, like ‘grapes’, and a human-readable label, like ‘Bunch of Grapes’. These are generally very similar but sometimes quite different – for example, most of the furniture art was sliced out of room art by Lottie, and I originally used her temporary names but changed the labels when I was writing copy:
… which nicely why it’s useful to have a stable ID – I didn’t have to go back and change all the config every time we decided it was a ‘Snug Chair’ not a ‘Cosy Chair’.
Lots of ids follow a convention, too. ‘Sky Stories’ has the id ‘s.skystories’ so I know it’s a skill when I’m writing content code. And it’s much easier if they’re consistent with each other, but ‘consistent’ is subjective. ‘s.skystories’? ‘s.sky.stories’? ‘s.sky_stories’? What about ‘Transformations & Liberations’? What I settled on was that ‘&’ in skill names is replaced with a . and spaces are just removed, which is different from the furniture convention but means I don’t have to look at ‘transformations&liberations’ or convert it to ‘transformationsandliberations’ or anything else ugly. Okay? still with me? a few of us? okay. Break out the good Scotch, Ponsworth, these are the real connoisseurs. San Pellegrino for the teetotallers.
To keep everything 100% consistent, I put a formula on my Skills and Abilities tab that converted the human-readable label into the ID according to a consistent set of rules. So it could never get out of step. Then I output the skills json. All written up, all consistent. Lovely.
Except the language skills were s.vak, s.killasimi, s.fucine… s.deepmandaic. Deep Mandaic was the only one with two words in the name, the inconsistency annoyed me, and a couple of times I typed it as ‘s.deep.mandaic’ so one day I just changed it to ‘s.mandaic’ everywhere, one big Find-Replace, no problem. This also addressed the plaints of a couple of very consistency-oriented people who thought it felt like a mistake that ‘Deep Mandaic’ was alphabetised under ‘D’ rather than ‘M’ (actually, alpha ordering via ID and otherwise in the game is a whole different story later, but there isn’t enough single malt in Scotland for that one).
Then I realised that I had broken my nice formula-driven consistent naming system. So I went back into the Skills & Abilities tab and manually overwrote it. I was in a hurry. And it was probably fine, probably. So I went back into Skills & Abilities and manually overwrote it rather than adding a distinct override column. Here it is! It’s just one value! What harm can it do? I put it in italics to remind myself! and Excel has a nice helpful Inconsistent Formula notation!
Here a third spreadsheet tab enters the story. (Top up their glasses, Ponsworth, come on man, quick sticks there.) This is the Tomes spreadsheet, a list of all the books in their game and their properties, which is auto-output like most of its kin.
Between you and me, and now we’re a couple of whiskies in, I’m going to confess that Excel is probably my favourite piece of software ever. It’s not a database, it’s not a word processor, but for the sweet spot for a system-oriented but distracted and arbitrary game designer, it’s a gorgeously customisable tool that supports all kinds of bizarre one-off requirements. Some of which come back later to bite me. Like that last column above with its 0 or 1. What’s different about Greek? There’s no Greek skill. All Hush House librarians know Greek. It’s just a bit of flavour that affects visitors. So Greek books don’t need a language slot. So I had a formula that checked whether a language with this name existed in my Skills & Abilities tab. And for this kind of lookup, I usually look up the label, not the ID, because it’s much more human-readable. But in this case I also wanted to output the language ID into the JSON which determined the slot that should go on the book. So I got lazy and I just stripped the spaces out of the human-readable label I found in this column, lowercased it, added an “s.” and wrote it into the json. Because the nice thing about language skills was, the label and ID were always identical if you did that! Vak, “s.vak”, Fucine, “s.fucine”, Deep Mandaic, “s.mandaic”…. ah.
This is where I compounded my first, cardinal, sin with a second, venial, one, for does not the Church of the Unconquerable Sun teach us that there is never only one Cloud to obscure the Light? Instead of changing the logic, I just went through and edited ‘Deep Mandaic’ to ‘mandaic’ throughout the Tomes spreadsheet.
FINE ALL FIXED LET’S PUSH WHATEVER URGENT PATCH NEEDS PUSHING.
The game grew more stable under my increasingly calloused hands. I even found some time to pay off a bit of technical debt. I reordered some of that which had been disordered. And so at at some point I did something careless. I can’t remember exactly how or what now. Tidied up ‘mandaic’ to ‘Deep Mandaic’ in the Languages column of the Tomes sheet? autofilled the ID formula down Skills & Abilities? Whatever it was silently broke my innocuous little formula hacks. In a constantly changing spreadsheet with 44 tabs, it’s not hard to lose track now and then.
Then at some later point I ran another output from the spreadsheet, and put it in another build, which I then at some other later point pushed live, immediately erasing all the Deep/Mandaic slots.
A week later I sheepishly came back in fixed it so I could output a non-broken version of the game json.
Finis. Except –
THREE MORE MISSING SLOTS
The following day I was fixing one of the bugs above (Hendrik, I think) and I USED AN OUTDATED VERSION OF THE SPREADSHEET BECAUSE I WAS ON MY LAPTOP AND HADN’T SYNCED EVERYTHING. All the Deep Mandaic slots disappeared, again. I fixed them, again.
F I N I S.
Ponsworth, I think we’re finally done, please fetch the coats and also the hats. Ponsworth? Ponsworth? Somebody wake up Ponsworth, he’s dribbling again.
TWO INPUT DEVICES
Usually, it’s my fault. Occasionally, it’s not my fault. Here’s a standard prefatory response I now send when someone reports mouse control problems.
“(1) I had a similar report from another user a couple of weeks ago… they later followed up and said they had a second input device attached to the machine that they’d forgotten about. so it’s worth checking that :)”
AND A RAGDOLL IN A BUST NICHE
The week after launch, I had this email from bug reporter M.S. :
“Hello, I found a very important bug in the game: you can’t put your cat on top of the bust pedestal in the grand ascent. Here, I’ll send you a picture of how it should look:”
This is the picture he sent:
I’m happy to report that fixed this bug in the next patch. And then, much later, I added another feature to the Thirteenth Librarian niche that not many Librarians have yet noticed.
Happy Christmas. May your Januaries be bright and your Februaries tolerable.