Slack on a SNES
I recently learned that in the mid 90s in Japan, the Super Nintendo had a peripheral called a Satellaview, which was a satellite modem that would receive data broadcasts from Nintendo.
Are you thinking what I’m thinking? Probably not, but if you can beam satellite signals to a SNES, you can probably run Slack on it.
Most SNES games are closed systems. When you play a game like Bronkie the Bronchiasaurus, an educational game about dinosaurs with asthma that teaches you how to use an inhaler, the content is fixed on the cartridge.
But the game that comes with the Satellaview, BS-X: The Story of The Town Whose Name Was Stolen (BS-X それは名前を盗まれた街の物語), is different. It looks like a lot of Japanese RPGs but has one key difference: it can receive content beamed from the sky and that content gets integrated into the game.
First, we need an emulator. Thanks to the hard work of LuigiBlood, there are two emulators that support the Satellaview natively: bsnes-plus and SNES9X. I chose bsnes-plus because SNES9X’s Satellaview Signal Data file support is only in the Windows build. I couldn’t find an OS X binary for bsnes-plus so I just compiled it myself.
Next we need the BS-X rom, which is available here. I used the patched English + No DRM version.
Finally, we need a controller. You can buy cheap USB SNES clone controllers on Amazon, but if you have an old SNES controller lying around, I recommend getting this 8BitDo Mod Kit. You can then connect your original SNES controller via Bluetooth to your Mac, or to an actual SNES or an Analogue Super NT with a Retro Receiver.
Now you can start the BS-X base game, create a character, and walk around town, but you’ll soon find that the town is pretty boring because there’s no content being beamed to it via satellite.
Satellaview would broadcast content every day from April 1995 to June 2000. Here’s a list of all the broadcasts that were made during the lifetime of the service.
Using a tool called SatellaWave, you can generate your own Satellaview Broadcast binary files. This is what it looks like:
This allows you to take one of the buildings in BS-X, set its name, and list items for sale in the building. Each item has a name and a description. If we stretch our imagination a bit, the name can be the time and sender and the description can be the text of the message.
So we have a way of getting data into the system, now how do we automate that process? The tool SatellaWave has the ability to save your current configuration as an XML file. It also allows you to export the Satellaview Broadcast binary files into a directory.
I’ve never written any .NET before, but how hard can it be? We’ll fork this program to disable the UI and accept two command line parameters: the XML file as input and a directory to export into. Here’s what that fork looks like.
While modifying this code, I discovered that Visual Studio for Mac exists and that you can actually compile and run .NET apps on OS X using an implementation called Mono. The UI looks terrible but we’re stripping it anyways.
Okay, but now how do we generate the XML files? We can create a configuration using the UI, save it as XML and look at its format:
<?xml version="1.0" encoding="utf-8"?>
<bsx version="0.1">
<channel name="Town Status" broadcast="1.1.0.5" lci="0120" timeout="10" type="2">
<town apu="3" radio="1" npc="0000000000000000000000000000000000000000000000000000000000000000" fountain="0" season="0"/>
</channel>
<channel name="Directory" broadcast="1.1.0.6" lci="0125" timeout="10" type="3">
<directory>
<folder name="#filth" message="#filth" purpose="1" type="0" id="2" mugshot="14">
<file name="5:00pm @bert" id="0" broadcast="1.3.0.0" lci="0127" timeout="10" type="5" description="The quick brown fox" usage="I use the item." price="000000000000" oneuse="false" path="" autostart="0" destination="0" home="false" streamed="false" month="1" day="1" starttime="00:00" endtime="23:59"/>
<file name="5:01pm @bert" id="0" broadcast="1.3.1.0" lci="0128" timeout="10" type="5" description="jumped over the lazy dog." usage="I use the item." price="000000000000" oneuse="false" path="" autostart="0" destination="0" home="false" streamed="false" month="1" day="1" starttime="00:00" endtime="23:59"/>
</folder>
</directory>
</channel>
<channel name="Welcome Message" broadcast="1.1.0.4" lci="0126" timeout="10" type="1">
<message>You look nice today.</message>
</channel>
</bsx>
So we have an idea of the general format, we just need to add files as children into the folder tag. It looks like there are two attributes that are incrementing, broadcast
and lci
. broadcast
looks pretty self explanatory, the third number just keeps incrementing, but it’s harder to discern what’s going on with lci
. If we look at the Satellawave source, there’s a function called GetNextLCI().
public static ushort GetNextLCI()
{
ushort nextlci = 0x0120;
while (CheckUsedLCI(nextlci))
{
nextlci = (ushort)(nextlci & 0x1F | (nextlci >> 3));
nextlci++;
nextlci = (ushort)(nextlci | ((nextlci & 0x3E0) << 3) | 0x0020);
}
return nextlci;
}
This is actually pretty easy to port to Javascript:
const pad = require('pad-left');
var lastlci = null;
function getNextLCI() {
if (lastlci == null) {
lastlci = 0x0120;
} else {
lastlci = (lastlci & 0x1F | (lastlci >> 3));
lastlci++;
lastlci = (lastlci | ((lastlci & 0x3E0) << 3) | 0x0020);
}
return pad(lastlci.toString(16).toUpperCase(), 4, '0');
}
So if we have a way to generate the XML configuration file and run it through the modified version of Satellawave to generate Satellaview Broadcast binary files, the last part is relatively easy. We’ll create a bot user, use the Slack Events API to listen for new messages in channels that we’re in and then call channels.history to retrieve the last 10 messages in the channel. Every time a new message is posted, it will push the new broadcast files into a directory that is monitored by bsnes-plus which will receive them as satellite data.
That’s it! Follow your dreams, even if your dreams are stupid.