Electron Dance
26Mar/1831

The Citadel Reborn

This is the sixth part of The Ouroboros Sequence, a series on puzzle games.

23 Dec 2013. Boson X and Dissembler developer Ian MacLarty tweets, "Have you had a go at PuzzleScript? Citadel looks like it could have been made using it (without the lives and timer)."

He's talking about the game I released in 1993, a Sokobanlike made in a time I'd never heard of Sokoban. I reply to MacLarty: "BUT THE LIVES AND TIMER ARE CRUCIAL (lol) I haven't checked out puzzle script; walk away from potential time sinks... Maybe l8r?"

The jerk fires back, "I don't imagine it'd take you long to learn. Oh and it also allows the player to *undo any number of moves* ;)"

Over four years later, last Wednesday to be precise, for some reason that I can't fathom, I started tinkering in PuzzleScript for the first time. On Saturday, I released a game on itch.io.

The Citadel is back, kids, and you can play it in your desktop browser right now. Let's talk a little about that.

WEDNESDAY: A WHOLE GAME JUST LIKE THAT

Every time I'd rifled through the PuzzleScript notes, I'd be like, what I don't even. This is code that says the player can push crates:

[ > Player | Crate ] -> [ > Player | > Crate ]

I gathered it was something to do with "the player is moving towards a crate so, er, okay the crate also moves". I don't have time for something that looks like very long RegEx. And that was how it remained year after year.

Whether it was the constant dribble of PuzzleScript prototypes from Aaron Steed's itch.io account or some other form of sexy synchronicity, I found myself in the PuzzleScript code editor on Wednesday. I don't know how I ended up there, absolutely no idea. And something happened in there, something wonderful. The code editor was so lean and friendly. Syntax colour coding. Instant compile and test. Examples available instantly from dropdown. I had no idea Stephen Lavelle had put together this and this was coding heaven.

Within minutes I started forging together rules a remake of The Citadel would need: pushing boulders, pushing blocks and pit logic. I even cobbled together a single teleporter. At the close of Wednesday, I had this:

Writing a game again was addictive. How addictive? I stopped playing Subnautica (Unknown Worlds, 2018).

But there were two really big problems.

THURSDAY: EXPLOSION

On Thursday, while I worked, my conscious mind kept turning its attention to the implementation of bombs. PuzzleScript, you see, does not do diagonals.

The Citadel called for bombs which explode in a neat box shape, like you might have seen in classic Boulder Dash (Peter Liepa & Chris Gray, 1984). It would've been relatively easy to implement a cross-shaped explosion with the bomb at its centre, but that would've broken half a dozen puzzles. I had to make sure I could hit the points diagonal from the bomb.

I considered invisible objects I termed "explosion seeds". These would explode out across the four compass directions, and then those objects explode out again, in one direction, to reach the corners. However, almost every bomb level has multiple bombs exploding simultaneously, so I needed to make sure all these seeds didn't overwrite each other. I built this "exploding seed" logic and after some debugging got it working just right by the time I went to bed on Thursday. The final release version turned out to be quite different as every day brought more PuzzleScript experience:

All good. But the other problem was way, way worse.

FRIDAY: HERE AND WHERE

On Friday, while I worked, my conscious mind kept turning its attention to the implementation of teleporters. PuzzleScript, you see, does not do any sort of configuration data.

The Citadel implemented eight different teleporters, all of which looked identical, but the wiring between them was level-dependent. Teleporter 1 might connect with teleporter 6 or 4 or 3. And that was something PuzzleScript just did not do. There were no variables or even general support for numbers because PuzzleScript wanted you to think in terms of objects and their interactive properties.

I considered doing a big ol' analysis on the config and reducing the level design to the optimum number of teleporter relationships needed. But that was not going to be fun and meant reproducing the levels was going to be horrible. I'd have to translate each level from a straightforward "teleporter 1-8 with connections" into "use teleporters 6, 9 and 10 that are connected in the correct way just for this level". Christ. I couldn't face it and you could just smell the potential for fresh, new bugs from here. The other possibility was...

Configuration.

I know, I know, I said PuzzleScript does not do configuration. But if the invisible bomb seeds tell you anything, it means you can scatter invisible objects all over the screen. Invisible objects could be used to implement a crude form of configuration data for each level. I originally envisioned creating "teleporter config" pairs at the bottom of the screen. But this didn't make me the happy programmer I wanted to be, either. I needed to create special invisible "in" and "out" objects for each teleporter. Instead of 8 teleporter objects in PuzzleScript, it would be 24. That's almost the whole alphabet. This is more serious flaw than you might think. You see, every level in PuzzleScript is laid out as an easy-to-read case-insensitive legend.

That's the third level of The Citadel. The teleporters are marked "1" through "8", "P" is the player and "X" is the exit. I sensed a real possibility that the extra 16 characters necessary to support the teleporter config objects were not available - particularly as PuzzleScript does not distinguish between lower and upper case. What I really, really wanted was to have a natural configuration based on the teleporter objects themselves. In other words, I could just write the teleporter connections using the teleporter objects themselves underneath the puzzle:

Teleporter 1 takes the player to teleporter 2. Teleporter 2 takes the player to teleporter 6 and so on...

There were still two significant drawbacks to this approach. This teleporter-based config was not invisible:

Aha! By surrounding them with special "shadow" objects, I could ask PuzzleScript to fill shadow objects over the top of them before the level begins. The player would have no clue. Great. Now for the other drawback. As they were teleporter objects, they was always a possibility that PuzzleScript would get confused and think these hidden teleporters were the real ones! Fortunately the solution to drawback one was also the solution to drawback two. Once the "shadow" had been drawn across them, I could distinguish between the real and configuration ones.

It was the perfect solution... although the coding took a crapload of tweaking before it worked as intended. Here's the code with the repetitions for each teleporter taken out:

With the teleporters done, I was encouraged to keep coding into the wee hours of Saturday morning because there was only one more real job left. It was time to replicate the original levels. I had no intention of copying all the levels down by hand, or even using the hand-drawn version of the level prototypes I still had in my possession:

Nope, nope and nope. You see, I still had the original assembly language files held on Atari ATR disk images. And the Atari emulator Altirra has this wonderful function that allows you to copy and paste the contents of Atari files anywhere you want. That was all I needed.

I copied the screen data into LibreOffice where I got to work straight away on developing formulae which would translate each level into PuzzleScript legend data.

Level data translation: Click for original size

It was not as clean as I had hoped because for some reason I had compressed teleporter configuration into nybbles (so 2 per byte). Nonetheless, I had the entire game working with all the original levels. That should have been it, right?

SATURDAY: LEARNING TO STOP

What kept me from releasing it on Saturday were the graphics.

PuzzleScript gives you all the colours in the world but it doesn't give you much resolution. Each object is 5x5 pixels and that's it. I was concerned that some of the different objects just wouldn't look distinguishable enough and I didn't want to rely heavily on colour because (a) doing that would make it looks like a dog's dinner and (b) you don't really have 16,777,216 colours but a much smaller set of distinct choices. The blocks, for example, looked identical to "stuck" blocks and very similar to the walls. Similarly, the grey colour of the boulders didn't signficantly differentiate them from the walls.

I played around a lot with the colour schemes and object shapes and probably spent over an hour working on alternative wall designs. But nothing looked as nice to me as the wall design that I'd been living with for a couple of days. What seemed to fix this impasse in the end was to make stuck objects red with an "outlined" motif and swap the boulder's grey for brown. Once that was done, I seemed to be at peace. Everything looked more legible and I was encouraged to work on smaller elements that I wasn't happy with - so the exit became a cone and the detonator a red swirl.

I knew I could've kept tweaking forever but it was time to stop. I released the game quietly late on Saturday night only for Aaron Steed to tell everybody about it.

And that was how I remade The Citadel in four days. Play now on itch.io. If stuck, you can always consult the walkthrough and level-by-level commentary. The game is free but if you do feel compelled to throw money at the screen, please throw it at my children's rugby club instead who are currently crowdfunding.

But, dang it, PuzzleScript is one excellent tool for making little blockpushing games like this, so full respect to Stephen Lavelle for putting in the hours on this one. If you're looking for another PuzzleScript creation I've found entertaining in the last week you might try The Flames (Rosden Shadow, 2017).

Next: Okay, developers, we need to talk about my agoraphobia.

Download my FREE eBook on the collapse of indie game prices an accessible and comprehensive explanation of what has happened to the market.

Sign up for the monthly Electron Dance Newsletter and follow on Twitter!

Electron Dance Highlights

Comments (31) Trackbacks (0)
  1. Impressive porting!
    Tip: you can use hexadecimal color representations in addition to keyword colors ( #ff0000 is red, for example)

  2. Hello Marcos! I think my wording is perhaps not clear here. I was aware Puzzlescript could draw from the 16m colour pallete and a lot of the colours in the game are set via hex – I just wanted to convey that you still end up facing a limited number of “distinct” colours – that a bunch of colours near each other on the colour wheel will not be dissimilar enough.

    Incidentally, I was expecting a ‘hack’ button on the html but it didn’t seem to be available. I didn’t intend to hide the code.

  3. (hack button only appear on shared games, not standalone ones)

  4. Ah, thanks anon. I will have a look at what “sharing” means in the context of PuzzleScript.

  5. Okay I’ve now added the full PuzzleScript source code to the itch.io page.

  6. Sweet article. I enjoyed your description of your first experiences with PuzzleScript–it really does look pretty alien until it suddenly clicks.

    Here’s my favorite trick for making diagonal explosions with only one seed object:

    [ STATIONARY XSeed | NO Bombproof ] -> [ XSeed | > XSeed ]
    [ PERPENDICULAR XSeed | NO Bombproof ] -> [ PERPENDICULAR XSeed | XSeed ]

    The first line puts explosion seeds adjacent to your seed “moving” outward, and the second line puts explosion seeds next to those, but only in the direction perpendicular to the way they’re moving.

  7. This is awesome.

    Sorry if this is obvious, but instead of masking the teleporter gubbins you could make the map a few rows taller and use the ‘flickscreen XxY’ setting to hide them away offscreen.

  8. I found you and your content last week and have been consuming quite a lot of it within that time. But then in the next article, you reference my small puzzlescript game. Which I find both surprising, funny and really spooky at the same time.

    I can definitely relate to trying to figure out (and having difficulty with) how to do things within puzzlescript that are some of the simplest things to do within other engines.

  9. Fantastic! I’m currently stuck about halfway through and resisting looking for a hint so far.

    Fascinating to read about your development experience too – did you work through entirely using internal docs/examples or look at the source of other people’s games for help? The vast majority of puzzlescript games being open-source (and the tooling directly encouraging that) seems like it could create an amazing ecosystem!

  10. Jonah

    Thanks! That’s really interesting. So the seeds don’t actually move but the moving is repurposed to paint them with a direction! I think that’s the next level “up” on PuzzleScript tricks for me, I hadn’t quite reached there in my short time with the language.

    I’ve just been scribbling down consequences and I suspect this trick wouldn’t work for The Citadel. The reason is multiple bombs go off. Suppose you have bomb 1 and bomb 2 one space SE of the first. Bomb 1 would generate a east-moving seed to the east. Bomb 2 would generate a north-moving seed in the same place. Both seeds exist in the same collision layer, so before we get to the PERPENDICULAR line, one of the seeds has been overwritten, which means one of the diagonal explosions will not be generated.

    I can’t quite see how to rescue this unless we can paint the seeds with different information indicating they need to reseed in all directions. Originally I had “cross” seeds that the logic would generate if it detected an overlap of H/V seeds. I later replaced this with H and V seeds in different layers, so they could co-exist without need for cross seeds which felt neater to me :) We all like getting rid of unnecessary objects!

    Robin

    No, no, that’s not obvious to me – still a PuzzleScript newb! Great idea. I did notice the Flickscreen option but it never occurred to me that I could just use it to hide stuff. And the original game was developed with a fixed frame size (20×11) so it would have been easy to enforce.

    I think I’d still need to come up with some form of invisible masking, however, to ensure the main engine never got fooled into seeing these as real teleporters and support the config-seeking algorithm.

    Rosden

    Hi! I think what happened is that during my PuzzleScript research last week I found The Flames on itch and really loved how tight the design was – it’s getting another reference in the next Ouroboros post as it is relevant – and I followed you on itch. That’s probably how you ended up here today :)

    I think those of us who like puzzles probably perceive of attempting to bend the small rule set of PuzzleScript to our will as just another puzzle. I felt such joy when I realised the seemingly out of reach mechanics of The Citadel were actually viable.

    Phlebas

    I’m endlessly curious as to which particular puzzles are considered hard, as the feedback I had on the game’s puzzles during the original development was limited to two people. Can you describe which one it is?

    On development: I worked mainly from the documentation but when functionality was unclear, I turned more towards posts on Google Groups and some of the blog posts out there (e.g. this tutorial). Code in the wild was less helpful than I expected. I did check out the code of other games – like Ben Davis’ death-defying PuzzleScript demake of Threes and Aperture Science Sokoban Testing Initiative – but without verbose comments I found it difficult to reverse-engineer intent. This was more useful if you fully understood PuzzleScript and were looking for cool ideas to stretch it.

  11. I’m pushing lots of squares and trying not to blow up the exit, if that tells you which one it is.

  12. Aha, yes it does. I realised later that the detonators are just walls – you can never step on them – and do not add anything extra to the puzzle. But they provide a different kind of theme to the level. I’m pretty sure there is a better level in there somewhere, where you can step on a detonator safely at some point.

  13. As far as the actual solution goes they’re just walls, but I’m finding it a lot tenser to play than if they were!

  14. I finished Flames! Nice job Rosden. Also cool to see the variations that can be done with a Sokoban-ish engine; I don’t remember ever seeing a Sokobanlike with this kind of theme. The one with the long fuse might have taken me the longest, partly because I’m not used to optimizing my moves, though I took a long time with (long description omitted, it’s the SECOND FREAKING LEVEL) before I solved it and felt stupid for having taken so long.

    One thing I really like about this is the way the mechanics naturally lead to reversing the polarity of the elements, as it were–sometimes you have to avoid setting things on fire, sometimes you have to find a way to set things on fire, sometimes you have to avoid setting things on fire until the moment when you have to set them on fire (or at least you’re close enough to done that you can get away with setting them on fire). Sometimes things are functionally walls and sometimes they’re walls until the very end. The level of Citadel with all the teleporters in vertical columns had that sense too, not with walls that become walls, but with polarity reversing–the topology of the space changes as the level progresses. I haven’t finished Citadel yet, I think I’m on the level after Phlebas’s.

    In the old style wasn’t there a functional difference between detonators and walls in that level? Bump into a wall and you waste a little time, bump into a detonator when you don’t want to and you’ve lost a life.

  15. Matt, I haven’t finished The Flames yet. I got to 8 out of 10 so far :) It’s always fun to see a new mechanic which is straightforward, unfamiliar and requires a different kind of thinking. The only “downside” is that it requires explicit counting of steps; it becomes very important for some levels and that *feels* less pure to me. I don’t have better words to express that right now. It’s late, I’m tired.

    That level of The Citadel you’re referring to is one of the very first I designed and remains my favourite. It’s a very tight level and can feel impossible on first glance. That feeling when you figure it out and the whole level opens up – I like that. A lot of puzzle games are about ordering or laying down structure, but this particular level is about going from real claustrophobia to control. I’ve no idea if anyone else gets that for the five minutes they spend on it, but it was the template of a perfect level for me at the time. It’s not even particularly laborious like some levels can be.

    You’re absolutely right that lives meant detonators would have been different to walls, but I think from the perspective of a puzzle to be solved, they’re identical because there are no conditions under which you would want to step onto a detonator. (Plus, I feel like the lives and time limit are an affectation, today, which strips them of that slight functional nuance.)

  16. Thanks for playing matt.
    When it comes to developing puzzle games (or any game in general) I try to work under the rules of using versatile mechanics and creating levels that feel EXPERIENTIALLY different with trying to only use those few mechanics.

    What I mean by versatile mechanics is 2 things.
    One is more along the lines of elegance or interconnectedness. For example let’s say I have a button I would want that button to be able to interact with any object that lands on it (e.g the player, a block or an enemy) because this would allow for a lot of different interesting events to be able to take place. For example a puzzle could involve trying to get an enemy to step on a button or the player could step on the button to allow an enemy to move to a certain position.
    Two is uniqueness. In The flames I have two objects that burn. One is a block that once it catches on fire it eventually turns to ash and the other one is a wall that once it catches on fire stays on fire forever. These unique qualities allow for more interesting events to be possible without having to introduce in new objects.

    Now on to what I mean by “levels that feel experientially different”. Levels that feel experientially different to me are levels that get the player act and/or think differently than other levels in the game. They can either feel minor (for example: the difference between pushing a barrel to avoiding a block and pushing a block to avoid a barrel) or feel major. These major feeling are more puzzle types here’s three that are found in The flames: The normal eureka effect puzzles, Build up puzzles (The puzzle which involves chaining block to make a path for the fire to get to the other side) and elegance based puzzles. To me working towards “levels that feel experientially different” have 3 benefits. One they can rejuvenate players when they start a new puzzle (though at times only slightly).Two they allow for puzzles to be able to feel tight because these puzzle don’t need the level to build too much off of the complexities of the previous levels. And three, they almost always inherently have a feeling that the player is learning something new in them because most times they are even its only seeing what they had known before in a new way.

    Well I guess I just summed up the major parts of my design philosophy in a comment. XD
    So if you did want to know how I thought when I designed The flames here it is. personally I believe level 9 is poorest level in the game so it is anyone’s least favourite level I understand.

  17. Hmm OK I think the reason I don’t tend to like step-counting levels is that they often involve working with minutiae rather than coming up with an overarching theme. And also, even with infinite undo, there’s a big possibility for the thing that St33d was complaining about with Stepheen’s Sausage Roll–you work out something at the end, and you realize you must have messed up a step at the beginning, so you go back and fix that, and now you have to remember how to do the end part.

    The thing I liked about level 8 of Flames is that I was eventually able to work out that a big part of it was limiting the number of changes of direction I made… there was a trick or two to optimize, but the biggest thing about it was the number of changes of direction, which gave me a heuristic that let me solve it once without counting in my head. Though this still didn’t allow me to parse the level enough that I was able to figure it out again when I played it just now. Alas.

    Level 9 was OK as I recall–the main worry I had was that I was going to do a bunch of stuff away from the exit and I wasn’t sure that the stuff near the exit would work, which would’ve been very annoying, but that stuff did work the first time through for me.

    Alas, I had to restart my computer and this lost my progress in Citadel. (You know what would improve the experience for both these things: Level selects!)

  18. Quickly – with the help of Aaron Steed, we’ve identified the saving problem, because all PuzzleScript games should save your progress. If you upload to itch.io as an HTML file, it does not save progress – only if uploaded as a ZIP file. I’ve now reuploaded as a ZIP and it saves your progress!!

    Rosden – this also affects The Flames. (I’ve had to play through once from the beginning again once, going to have to do it again to finish the game…)

  19. Is it ironic to anyone else that creating a puzzle game in PuzzleScript is in itself a puzzle for the developer?

    Great site you’ve got here, I’ve really enjoyed your articles. Was wondering if you’ve played Aaron’s Rustbucket yet? One of my favs.

  20. I knew about the problem very early on but I thought I couldn’t do anything about it.

    I tried your solution for myself but it didn’t fix it for me. I went to try saving on The citadel and it didn’t work there either. I did use your solution so it should save for you now but for some reason it didn’t work for me.

  21. My computer rebooted itself, so I had to start again. Thankfully I remembered the trick to the one I got stuck on before – and I’ve just finished the game. Thanks – I enjoyed that!

  22. Goddamit Joel, I’ve only just read this the day after I left for a two month camping trip where I don’t have a desktop browser! Hope I remember to play when I get back.

    In the meantime, I loved the story of the rebirth, especially the spreadsheet formula transform bit – I occasionally have to do similar things at work and I find it most therapeutic.

  23. Ah, right. Now I can come back to the comments at last. Life is not playing fair right now.

    Josh

    Hello Josh and welcome! I hadn’t heard of Rustbucket until now, so there’s your answer :)

    I think “PuzzleScript being a puzzle” is what encourages people to make crazy stuff in it. I already have an idea for something, to see how it might be done, as opposed to creating a fabulous game.

    Rosden

    You’re right, it does work for me now. Which is good because I’ve been stuck on the eighth level for awhile. I need to play when I’m less tired!

    Sorry the solution doesn’t work for you.

    Phlebas

    Phew, well done The game is quite long with 26 levels so I’m glad I got the saving fixed. I don’t want everyone to go through the same issue you had of having to replay from the start!

    Incidentally the feedback elsewhere has been positive. Over at bontegames and Reddit.

    Kfix

    Sorry my friend! All I can say is that I’m off on a week-long holiday from tomorrow so you likely won’t be missing out on anything else over the next week!

    Oh half my office life is Formula transform work. It was just another day at the office out of the office for me.

  24. The continue game still isn’t working for me. :-(

  25. Away on holiday but won’t stop me from sending this quick question…

    To Rosden & Matt – what OS and browser are you using?

  26. Mac OSX 10.11.6, Firefox 59.0.2. (I also often experience flaky behavior on other sites.)

  27. Windows 8 – google chrome

  28. Posted extra info about the save game issue to Twitter.

  29. Rosden, Matt, being asked if it makes any difference if you use incognito/private mode in your browser. This is a slightly intricate test because you mustn’t close the mode – just close the tab and open another within the same incognito/private mode.

    @moonscript is wondering if this is due to cookie conflicts.

  30. I opened the link in a new private window, played two levels, opened a new tab on the window, copied the URL, closed the original tab, pasted the URL into the new tab, and reloaded… and got no Continue Game option. So no joy, I guess.

  31. Oops, that was me.


Leave a comment

Notify me of followup comments via e-mail.

No trackbacks yet.