I love Spelunky. I’ve been playing it almost every day for the last six months, and I never get tired of it.
Sometimes Jeff and I will be at the office, each of us playing Spelunky — inevitably, one of us will say, “Oh my god, you’ll never believe what just happened!” and then proceed to regale the other with a story of our latest randomly generated adventure.
A couple of weeks ago, I got an idea in my head that wouldn’t go away: what if I could make Spelunky update Twitter with these stories I love so much? And so I started right in on the project. (You can see the end result here: @darius_spelunks.)
The first step was decompiling the Spelunky source code. Spelunky is written in Game Maker 7, and so decompiling is pretty easy if you follow the instructions on the Spelunky wiki.
The next step was figuring out how to get Game Maker to update Twitter. It doesn’t come with native support for HTTP Post requests, so I had to improvise. I ended up going with a real kludge of a solution. There’s a user-contributed Game Maker DLL called SilentDOS, which lets you run stuff on the Windows command line in the background of your game. (There is a native GM7 function called execute_shell(), but the problem with that function is that it opens a cmd.exe window and disrupts your game.) To initialize SilentDOS, make sure that the DLL is in the same directory as your .gmk file, and then run this at the start of the game:
global.nnn = external_define(‘silent_dos.dll’,'RunSilent’,dll_stdcall, ty_real,2,ty_string,ty_string);
I put it in the create script for the oGame object in Spelunky.
So now I could run Windows command line stuff. This meant I could run wget, which is for making HTTP requests on the command line. Fortunately, it’s pretty easy to update Twitter with wget. I ended up making a file called tweet.bat, and put it in my C:\Windows\System32 directory:
IF %1==DNT (echo %1) ELSE (wget –http-user=”username” –http-password=”password” –post-data=”status=%1″ -b -q http://twitter.com/statuses/update.xml)
This uses a couple of tricks. First of all, it accepts a command line argument, and “%1″ is just the argument you pass to it. In this case, it’s the update you’re sending to Twitter:
> tweet.bat “Test!”
The IF statement just says that if the string I send is “DNT” (“Do Not Tweet”), don’t send an update to Twitter, just print DNT to the console. Assuming I didn’t send “DNT,” it runs the wget command. The “-q” command runs it in quiet mode so it doesn’t write any log files as outputs. The “-b” command runs it as a background process, so that it doesn’t block Spelunky while it’s trying to run. When I run it without “-b”, the game will pause for three seconds every time I tweet while I wait for the Twitter server to verify the post.
So now I can tell SilentDOS to run tweet.bat with an arbitrary string as an argument. The problem is that if I try to pass it a regular string:
external_call(global.nnn,”tweet”,”This is my status update.”);
the Twitter post ends up saying only “This”. It’s because the command line argument assumes that “This” is argument 1, “is” is argument 2, etc. So I wrote a helper function called format() to replace all spaces with “%20″, which is the hexadecimal URL encoding for the space character. The function also replaces commas with “%2C”:
message = ” ” + string_replace_all(argument0,” “,”%20″);
message = string_replace_all(message,”,”,”%2C”);
return(message);
So here’s the actual call to update Twitter from Game Maker:
external_call(global.nnn,”tweet”,format(“Your Twitter update goes here, with commas and everything!”));
At that point it was just a matter of experimenting with where in the code I could put the Twitter calls. My standard script for generating the text bits looks like this:
if (global.LastTweet == “scrTEnemySacrifice”) return “DNT”;
else global.LastTweet = “scrTEnemySacrifice”;
rInt = floor(random(4));
if (rInt == 0) return(“Kali had better enjoy this here ” + string_lower(argument0) + “. I work hard to bring her these sacrifices.”);
if (rInt == 1) return(“I slave all day to bring you this ” + string_lower(argument0) + “, and what do I get? A random prize determined by a favor counter? Please.”);
if (rInt == 2) return(“Oboy I love sacrificing a nice ” + string_lower(argument0) + “.”);
if (rInt == 3) return(“Sometimes, life is tough for me. But then I sacrifice a ” + string_lower(argument0) + ” on an unholy altar and I remember that others have it worse off.”);
The first two lines are there because I had a lot of problems with updates that were too repetitive — who wants to read, “I whipped a snake” “Take that, bat!” “Oh man I just whipped a caveman” all in a row? I wanted more variety in the tweets, so those first lines ask: Did we just tweet about this kind of event? If we did, then don’t actually update Twitter with this. If we didn’t, then we pick a random phrase to tweet about. The argument0 in these functions is usually the “type” field of a given object, which is the English language name of the object. It’s formatted like “Caveman”, which is why I call the string_lower() function when appropriate.
So there you have it: a brief tutorial on how to get Game Maker updating Twitter.
{ 4 comments }
Great post, dude!
I'm glad to see people hacking with Twitter + games more these days (be sure to check out TweetMyGaming.com, which gamerDNA just launched, when it comes back up)
One of the things I look forward to with my current project is seeing what kinds of Twitter integration people enjoy. I think it could be a really neat tool for high-engagement users.
this is the Darius I know and love
"I am the Evil Spelunky Bomber What Bombs At Spelunky!"
LOVING the reference.
Haha, glad you like the reference, Erd. I figured somebody would :)
Comments on this entry are closed.