Source Code Amnesty Day 2026

Those of you anxiously checking your calendars are aware that a very important date is drawing near, wondering whether Source Code Amnesty Day will happen on April 1 – apologies, I meant to get something on this posted last week, but life has not been especially cooperative of late. And I just managed to carve a chunk out of one of my fingers while grabbing a wickedly sharp can yesterday, so my typing is more laborious and error-prone than usual. So as a result this post is late, short, and not as funny or engaging as I’d prefer it to be.

But! What, I ask you, could be more aligned with the I-feel-bad-about-it-but-I-should-release-it-anyway ethos of Source Code Amnesty Day than that?

Source Code Amnesty Day, as we all surely know by now, is the day when authors commit to releasing their source code as a public service, even if they have misgivings about the quality of their coding, the stability of their games, the obscurity of their Easter Eggs, or any of the million hobgoblins bedeviling the creative psyche. I get it! I get those hobgoblins too! But publicly-available source code is a wonderful resource for our community, whether you’re a new author trying to understand the different ways you could structure your game’s code, an old hand curious about how one particular trick was pulled off, or a reviewer or critic looking to enhance your understanding of a game’s mechanisms.

So every April 1, we take a deep breath, tell those hobgoblins to eat an Abi-Dalzim’s Horrid Wilting, and post the source code we’ve got rattling around to our archives of choice (typically the easiest thing is to upload to the IF Archive and then post the link in your game’s IFDB page). Why April 1? It’s just because it’s far enough into the year that you might have a cleaned-up version of last year’s Spring Thing or Comp entry, and be feeling less coy about it now that it’s been out in the world for a bit – though if you have older stuff, that’s more than welcome too!

The scab on my pinkie finger is aching, so rather than answer any more questions here I’ll just link to the inaugural 2023 thread that got this ball rolling, since it goes into more of the subtleties, though really the thing is dead simple: post your source code, then mention it in this thread so we can all offer some well-earned applause!

12 Likes

I did it now because I would have forgotten!

10 Likes

Congrats on getting things in early! And I think code for rarer platforms is especially valuable.

6 Likes

I’ve already released mine for the year, but I encourage everyone to participate!

If your game works, you’re doing it right :grinning_cat:

8 Likes

I too am early because I’m forgetful.

Phobos: A Galaxy Jones Story is now open-source: GitHub - rileypb/Phobos · GitHub

ĹıſĺĺļŁĽĿŀŧĹ!

7 Likes

I just realised that I haven’t actually released the source code of my last year’s ectocomp entry.

4 Likes

I’ll add both versions of the source code (the comp version and the postcomp version) to IF Archive later but I’ll just upload them here for now.
requiescat (comp).twee (21.9 KB)
requiescat (postcomp).twee (24.8 KB)

5 Likes

None of my source code is complete or neat or anything. So, instead, I’m giving a sneak peek at a routine from my upcoming game…

from the file "ending.zil":
<ROUTINE SPECIFY-AP-ROOM (NUM G)
     <COND (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,DEEP-UNDERGROUND>
            <TELL "the underground area">)
           (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,FRONT-YARD>
            <TELL "the front yard">)
           (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,YOUR-BEDROOM>
            <TELL "my bedroom">)
           (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,CHILD-BEDROOM>
            <COND (<PROB 50>
                   <TELL CD ,CHILD "'s bedroom">)
                  (T
                   <TELL "my ">
                   <COND (<PROB 50>
                          <TELL "child">)
                         (T
                          <COND (<IS? ,CHILD ,FEMALE>
                                 <TELL "daughter">)
                                (T
                                 <TELL "son">)>)>
                   <TELL "'s ">
                   <COND (<AND ,COMMENT-ON-POSH-CHILD
                               <NOT .G>
                               <PROB 13>>
                          <TELL "(who I found slightly annoying) ">
                          <SET G T>)>
                   <TELL "bedroom">)>)
           (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,KITCHEN>
            <TELL "the kitchen">)
           (<=? <GET ,WEIRD-DISAPPEAR .NUM> ,ENTRANCE-HALL>
            <TELL "the entrance hall">)
           (T
            <TELL "... well, honestly, I'm not quite sure where I was">)>
     <RETURN .G>>
7 Likes

But that’s the whole point! If we had perfect code, we wouldn’t need amnesty. :–)

[!quote] Source Code Amnesty Day 2023

A wise man once told me that what matters most in coding is getting the job done, and that clean code can be a kindness to your future self but isn’t necessarily the mark of an accomplished programmer. I really take those words to heart.

While I’ve been making efforts to fix and improve older games, and learning from my mistakes to improve my workflow in future games, I also try to embrace the messiness that can come with trying to make things work under time pressure & with imperfect knowledge. Redundant synonyms, inefficient / janky processes, reinventing the wheel instead of using built-in features, objects that exists only to store a single attribute, etc… but the code still mostly did what I needed it to do, and players still had a good time overall!

My own source codes are always available on my GitHub page. Shoutout to @aschultz who very kindly helped me understand how it all works, and who keeps lots of his own code on there too!

Sharing one silly and overcomplicated bit, in the spirit of SCAD:

[!question]- How hard can it be to choose a tie to wear?
The necktie is a thing with the printed name "[if the necktie is well-tied and the necktie is bamboozled]impeccably-tied [end if][if the necktie is well-tied and the necktie is semi-bamboozled]lovingly-tied [end if]necktie". Understand "tie" and "neck tie" and "neck" and "necktie" as the necktie.

The neckties is a thing in Hastings Bedroom. Understand "tie", "ties", "necktie", "neck", "red", "green", "paisley", "pasley", "pais", "pai", "gre", "paisly", "paisely", "pasly", "red tie", "green tie", "paisley tie", "red necktie", "green necktie", "paisley necktie" and "neckties" as the neckties.

The rtdesc is a thing.
The gtdesc is a thing.
The ptdesc is a thing.

Before examining the neckties:
if the player's command includes "red":
now the rtdesc is seen;
say "A classic red necktie which had served me well for many years." instead;
if the player's command includes "green" or the player's command includes "gre":
now the gtdesc is seen;
say "The green necktie was a relatively recent acquisition, and showier than my usual garb. I had not yet had many opportunities to wear it." instead;
if the player's command includes "paisley" or the player's command includes "pai":
now the ptdesc is seen;
say "The paisley necktie had been a gift from Poirot, before my expatriation. The little man has always been fond of that pattern." instead;
otherwise:
say "I had laid out a [if the rtdesc is unseen][bold type][else][italic type][end if]red[roman type] necktie, a [if the gtdesc is unseen][bold type][else][italic type][end if]green[roman type] necktie and a [if the ptdesc is unseen][bold type][else][italic type][end if]paisley[roman type] necktie, but had not yet decided which one to wear." instead.

Before wearing the neckties:
if the player's command includes "red":
say "I finally opted for the red necktie and put the others away. I was now ready to head down to my flat and take Bob on that dreaded walk[unicode 8212]but decided to allow myself the indulgence of a warm cup of coffee first.";
now the neckties is in the Park;
now the necktie is red;
now the objective is "have coffee (2/8)";
now the player is wearing the necktie instead;
if the player's command includes "green" or the player's command includes "gre":
say "I finally opted for the green necktie and put the others away. I was now ready to head down to my flat and take Bob on that dreaded walk[unicode 8212]but decided to allow myself the indulgence of a warm cup of coffee first.";
now the neckties is in the Park;
now the necktie is green;
now the objective is "have coffee (2/8)";
now the player is wearing the necktie instead;
if the player's command includes "paisley" or the player's command includes "pai" or the player's command includes "pasely" or the player's command includes "pasley" or the player's command includes "paisly" or the player's command includes "paisely" or the player's command includes "pasly":
say "I finally opted for the paisley necktie and put the others away. I was now ready to head down to my flat and take Bob on that dreaded walk[unicode 8212]but decided to allow myself the indulgence of a warm cup of coffee first.";
now the neckties is in the Park;
now the necktie is paisley;
now the objective is "have coffee (2/8)";
now the player is wearing the necktie instead;
otherwise:
say "I had laid out a [if the rtdesc is unseen][bold type][else][italic type][end if]red[roman type] necktie, a [if the gtdesc is unseen][bold type][else][italic type][end if]green[roman type] necktie and a [if the ptdesc is unseen][bold type][else][italic type][end if]paisley[roman type] necktie, but had not yet decided which one to wear." instead.

(Then an entire repetition of that last big code block for taking the neckties, because it didn’t occur to me that I could redirect the action…)

15 Likes

Every year on April 1st (yes, the day of “April Fools’ Day”), we celebrate the «Source Code Amnesty Day».
In 2026, the time will come for me to release the source code for «A winter morning on the beach», a rather unique interactive fiction presented at the IFComp 2025.
I’m a few days early, but I don’t want to get in the way of the final preparations for the Sping Thing: there’s always something to tweak at the last minute…
For those who can’t wait the complete project is available at GitHub.

For everyone else, I’ve created a page on my website where you’ll find a brief guide to the source code contained in the repository.

In fact, in addition to the classic Inform7 source code, which makes extensive use of hyperlinks, you’ll also find a modified version of the Bisquixe interpreter and a sample structure for a Progressive Web App.
I hope you like it.

9 Likes

I really like this sort of event. I usually keep my repos open after the game is published somewhere. I’m interested in what people have to say about my code. It’s also neat to see if I got any stars.

(I check maybe once every 3 months. I’m thrilled if I even get 1 star.)

As Allyson noted upthread I’m on github. I think a lot of my code early on was messy but I managed to clean it up.

If I don’t have anything I have to clean up, Source Code Amnesty still reminds me of what I want to.

@strawberryfield’s Winter Morning source code immediately showed me some neat things about the latest version of inform e.g. you can say /b … often just scanning source can help a ton, and it’s a bonus if you’ve played the game in question as you may say “oh that’s how they did that.”

8 Likes

I already released this back in December but I figure I might as well take the opportunity to mention again that the source code for both versions of Super Halloween Horror Show (the Inform 7 Ectocomp version and the Dialog rewrite with hybrid parser/choice interface) is on GitHub.

7 Likes

Thanks for the reminder.

I posted the source code for Kill Wizard on GitHub when I released the game, but I’ve been meaning to put the game/code up on the archive. This is a great reason to do it. It’s sitting in the if-archive/unprocessed folder right now. I’ll link to the IFDB once it’s done.

7 Likes

This is by far my favorite holiday that falls on April 1! I just added a source code file to the itch.io page for Swap Wand User. I forgot there was a whole level commented out in there, plus I conveniently noted “the funniest/most horrible line I’ve ever written in Inform.” My friend who is an expert coder said it has “some structural things that seem a bit painful.” Accurate. But it works!

12 Likes

Source code amnesty day inspired me to do my bit. I’m getting in early, as I knew I had a lot of work to do. And so…

The BDB Project now has a GitHub repository where you can see the source code for all the games that have been published so far. There is one repository for each game. Each repository includes the PunyInform source code, z5 story file, Trizbort map, png map and solution. Please not that this is not public domain, but open source. It is provided for educational purposes only. You can view the source code to see how we do things and borrow snippets to use in your own projects if you find anything that’s useful. You can find the new repository at: The BDB Project · GitHub

15 Likes

This was the catalyst for finally installing Git (as well as the interpreter!)

Here is the source code of Daddy’s Birthday, the only game I have published: GitHub - jonathan-intfic/daddys-birthday · GitHub. Here’s the IFWiki page for the game: Daddy's Birthday - IFWiki.

I might try to get my not-so-young-now co-author interested in improving the code, so if you have any ideas then feel free to use Github’s “Issues” or other features! Thanks in advance :slight_smile:

I’ve checked and git clone https://github.com/jonathan-intfic/daddys-birthday.git works.

Submitted a day early because I noticed midnight had passed but forgot March has 31 days…

5 Likes

After years of not getting round to this, I’ve finally put a repo up and added the source for my first game from 2019. At this rate it might be up to date by the year 2260 :roll_eyes:

Link to Github here.

The version of The Cave of Hoarding for which I added the source is the ‘Special Edition’ (version 0.2.0), released a year later in 2020. I’m afraid at this point I can’t remember what was ‘special’ about it. (Oh, hang on, it might have been some updated graphics because the originals were TRULY terrible.)

As noted in the readme, Adventuron has changed quite a bit since 2019 and so some parts of the code almost certainly won’t work!

Reading through the code I couldn’t believe how baggy it is. So embarrassing! It could have been about a third of the size that it is! But it’s sort of nice to feel that sense of progress.

10 Likes

I’ve added the participants (so far) to the IFWiki page at: Source Code Amnesty Day 2026 - IFWiki.

8 Likes

Okay, not really anything I think people would call IF, and it’s written in C++ instead of any of the languages built with IF in mind, but last night, I finally managed to force myself to take a look at my broken interface code for Micro Chao Garden, my attempt to demake the Chao Gardens from the Sonic Adventure Duology as text-only terminal games. Commented out anything related to ncurses and changed maybe a dozen statements using one of ncurses’s print functions to using cout and it now compiles and runs… At least on Debian Testing x86-64 compiling with G+±16, no guarantee it’ll compile for other platforms, though I have no reason to think any of my code is platform dependent.

I haven’t thoroughly tested the new build, and honestly, the date listed in the header comments in microChaoGarden.cpp suggests I last worked on this project seriously in 2017, so I’d probably have to do some code analysis of my own code to figure out where my implementation behaves differently from the inspiration. I can say for sure that trying to give an item to a chao will cause a segmentation fault, I suspect because my original animals.dat got lost or corrupted, and while I’ve downloaded data to make a new animals.dat, I haven’t yet formatted it to something the game can actually understand or added code so it fails gracefully if the file is missing or malformed.

The interface is kind of clunky, consisting of numbered menus printed to the screen and taking choices via keyboard input and lacking meaningful feedback on what effect player actions have… so, consider this a public beta at best. The game saves your chao to chao.dat, which is read automatically on launch and written automatically on exit via the exit option on the menu, though perhaps I should add an explicit save option…

No git repository yet, but source code and the game itself can be found at:

Sega has a reputation for being as laid back as Nintendo is uptight about fan projects, but I’m tempted to say public domain just to be safe since its a fan game…

the .bin file in the bin directory is the new build I made last night. the .elf file is an older, presumably x86-32 build from before I rendered my code uncompilable and I can’t even guarantee it will run on modern 32-bit editions of Linux if anyone is still running 32-bit Linux these days, it is provided primarily for archival reasons and I’m open to argument for getting rid of it. If anyone tries to compile it for anything other than x86-64 Linux, please let me know… can’t guarantee I can do anything about it if it doesn’t compile, but I’d like to at least be aware of incompatibilities.

Hopefully, now that I’ve gotten over the biggest hurdle that killed my motivation for this, maybe I can actually start working on improving the interface or extending the backend functionality… or at least fix that segmentation fault by tomorrow.

5 Likes

I suppose it’s a given that all Twine games already have their source code available to all, and since I’ve only written Twine games recently, that means I have no code to share, good or bad.

However, to save anyone having to dig through Dr Morben’s House of Terror to find anything of note, here are the two best (worst?) bits of code in it.

The first is the code I used to take the various built-in settings and saves dialogs and combine them into a single tabbed window with my own code:

[!example]- Code

$(document).on('click','#settings', ev => {
  setup.settings_dialog();
});
setup.settings_dialog = function(save_selected=false) {
  State.temporary.saveSelect = save_selected;
  $("#ui-dialog").addClass("system");
  UI.buildSettings();
  const $settings = $('#ui-dialog-body').children().detach();
  UI.buildSaves();
  const $saves = $('#ui-dialog-body').children().detach();
  Dialog.setup("System","system settings saves");
  Dialog.wikiPassage("System UI");
  $("#tabs-contents-settings").append($settings);
  $("#tabs-contents-saves").append($saves);
  Dialog.open(null,() => { 
    $(document).off('click',"#tabs-contents-saves *");
    State.temporary.saveSelect = false;
  });
  $(document).on('click',"#tabs-contents-saves *",function(e) {
    if (!$("#tabs-contents-saves").length) {
      $(document).off('click',"#tabs-contents-saves *");
      setup.settings_dialog(true);
    }
  });
};

Basically I’m building the built-in dialogs, stealing the content, and then attaching it elsewhere. The saves dialog makes that much worse, because it always rebuilds the dialog when you click a button, so I have to also trap that and build my own after each click.

The other bit of crime committing code is the <<panic>> macro, which increases player panic, but can also just stop a passage mid-way and prevent the rest of the passage being processed — this happens if your panic gets too high. It does this by abusing the internals of SugarCube.

[!example]- Code

Macro.add('panic', {
    skipArgs   : false,
    tags       : null,
    handler() {
      const v    = State.variables;
      const t    = State.temporary;
      const type = this.args[0] > 0 ? 'gained' : 'lost';
      v.panic = Math.max(1,v.panic + this.args[0]);
      if (!("notifications" in t)) { t.notifications = []; }
      if (v.panic >= setup.MAX_PANIC) {
        $(this.output).wiki(this.payload[0].contents);
        if (this.args[1] !== "silent") {
      		t.notifications.push({class:"icon panic gained max",text:`You've reached your breaking point!`});
        }
    	TempState.break = 2;
      } else {
        if (this.args[1] !== "silent") {
      		t.notifications.push({class:`icon panic ${type}`,text:`You ${type} ${Math.abs(this.args[0])} panic! (${v.panic}/${setup.MAX_PANIC})`});
        }
      }
    }
});

If you don’t reach MAX_PANIC then it just shows a message and the passage continues. The usage looks like:

<<panic 1>>
  <p>//No … you've been here too long already, too long. You have to get out of here!//</p>
  <ul>
  <li>[[You start to run|insane outside]]</li>
  </ul>
<</panic>>
7 Likes