I wonder if it’s wise to run a commercial showcasing just how much a pain in the ass Visa Checkout is. You just know the guys1 who made this were nudging themselves and guffawing, and then they went out for Starbucks and charged it to Apple Pay without even looking at their phones.

  1. I use “guys” gender neutrally, don’t you?  (back)

In order to put sprites behind me, I need to standardize time as the game sees it. Measuring it by milliseconds works, but makes synchronization difficult. There are also a bunch of gotchas in measuring time, like time zones, and friggin’ leap seconds, and what happens if someone’s playing when Daylight Savings Time kicks in?

Someone ought to think about that, I guess. In this case nothing happens, because we don’t care about what second it is so much as when the second it is now changes.

Presented without comment:1

Thursday Morning’s Record

August 9, 1928

Bumble Bee Attacks — A little bee caused an automobile to upset. George Crudden, advertising manager for Beck Bros., while driving along the Lancaster-Lititz highway, discovered a bee in his auto.

He batted at the bee with a newspaper, but the insect dodged out of the way. The bee got on his nerves and when he saw it dart for his eye he ducked his head. There was a crash when the auto hit the guard fence, breaking two posts and turned over on the side.

Mr. Crudden was imprisoned in the auto, his arm being pinned fast outside the window. An audience soon gathered. Someone suggested breaking the window to get him out, but Mr. Crudden, apparently cool, called out to them to wait.

With his free arm he opened the handle of the door and he was pulled out. Mr. Crudden has driven an auto for a number of years and he’s come through some “close ones” by keeping his nerve, but in the future he avers, when a bee or any other annoying insect enters his car, he will use safety-first measures and stop immediately.


  1. Source: http://lancasteronline.com/article/local/225595_1978–Elmer-Bobst-dies-at-age-93.html  (back)


Over the course of my consultancy and hobbies, I find it eminently useful to have a number of servers available for development, project space, file storage, and plain old web hosting. Most of the time, these needs aren’t major – so rather than plunking down $2,000 for a rack-mount server, I rent a number of small VPS1 systems as needed.

The majority of those are with BudgetVM, a company I was sort of impressed with until recently. Their prices are low, their website mostly works, and disk access is good. So naturally, when it came time to move development of a project off of my workstation, I spun up a new instance. CentOS, let’s match the deployment environment. Log in, install Apache, install Git. Almost ready for a coffee break. Git clone is running, the source is downloading. Fantastic! I punch out. I return ten minutes later, cup in hand. I notice Git is stuck at 95% – that’s odd, the codebase isn’t that big – but before I can dwell on it too much, I get an email.

Enzu Inc. <support@enzu.com> Winfield Trail, Thank you for contacting us. This is an automated response confirming the receipt of your ticket. Our team will get back to you as soon as possible. When replying, please make sure that the ticket ID is kept in the subject so that we can track your replies.

Ticket ID: API-642-39013 Subject: virt2.sudowned.com –
NullRoute Notification Department: Notifications Type: Issue Status: Pending Reply Priority: Normal Regards, The Support Team

This is pretty baffling. Thank you for contacting us? I did no such thing. NullRoute2 notification? That sounds ominous as hell. Oh, and it’s always classy to use my entire name in a form email. I log in and read the ticket:

Posted on: 2013-12-31 22:43:02
Dear Winfield Trail,
Our NOC has detected a network scan (or network attack) either originating or destined to an IP address under your responsibility. Please take the necessary actions to avoid this in future. Any feedback would be appreciated.

The IP Address: has been nullrouted the nullroute will be lifted at 2013-12-31 22:58:16 * Note if there are further event’s it will be NullRouted again for a longer duration. *

Device: virt2.sudowned.com – Netflow Logs
+ incoming: 177048780 bits/s Logged: 2013-12-31 19:27:22 Expires: 2014-01-01 07:27:22
+ incoming: 177048780 bits/s Logged: 2013-12-31 19:27:23 Expires: 2014-01-01 19:27:23
+ incoming: 164580556 bits/s Logged: 2013-12-31 22:43:11 Expires: 2013-12-31 22:48:11
+ incoming: 164580556 bits/s Logged: 2013-12-31 22:43:16 Expires: 2013-12-31 22:58:16
This is an automated message generated during the Null route process. Continued attacks will also be nullrouted and may generate additional messages.

This is ridiculous for several reasons. The machine isn’t compromised – I know because it’s brand new, there isn’t any code running on it that didn’t come packed with it or off an official CentOS distro. But I read the first paragraph again:  “…detected a network scan (or network attack) either originating or destined to an IP address under your responsibility.” What? So they NullRoute machines that are on the receiving end of a network scan? Are they insane? What security best practices state that automatically causing DoS attacks to succeed is a winning strategy? I don’t know what to make of it, so I bang off a reply:

Winfield Trail
Posted on: 2013-12-31 22:47:33
Your detection is either inaccurate or the issue is baked into your CentOS 6.4 x64 image. I created this VM less than three hours ago and literally all I’ve done with it is:

-Installed apache httpd + php5 (not configured, still offline), installed git
-Created user, added to wheel
-Disabled root login
-Initiated git clone operation (did not complete)

But hey, the server’s back up. Maybe it’s just a fluke, right? I log in, run git clone again. This time it’s almost instantaneous. Git stops at 50%, my email goes off. Another email, another identical ticket. This time the block is 24 hours. What? Seriously, what. This would be funny if it was happening to someone else.  I post another reply, which is definitely testier than it should have been:

Winfield Trail
Posted on: 2013-12-31 23:12:55
I tried once again to perform a simple git pull, and once again your system has disabled my VPS. Get it back online and disable this ridiculous filter or I’ll take my business elsewhere.

Well, it’s been 40 hours since then and there’s only been one change – they closed my ticket. No response, no feedback. This is about on par with getting the silent treatment while asking the waiter why there’s a log of used soil bobbing placidly in the tomato bisque.

Actually, I take that back: they sent me two surveys asking how they did with my support tickets. Unbelievable. Needless to say, I’m already in the process of moving my operation to someone who hasn’t ever disabled my server and disappeared for days.

The paint chips must be delicious in BudgetVM’s offices.

  1. Virtual Private Server  (back)
  2. Null routing a device kills its network connection. It’s more complicated than that, but it’s also very boring.  (back)

Things I like

  1. Sort of consistent UI
  2. Very nice icon dock
  3. Has a notification tray, kind of
  4. Doesn’t have a Desktop folder, so my wallpaper isn’t encrusted with nonsense that should be in my home directory anyway
  5. It’s not Unity, KDE, or Gnome 3

Things I don’t

  1. File manager crashes frequently
  2. Window contents are inexplicably slow to update. Sometimes they won’t update at all.
  3. Text editor is incredibly laggy
  4. Some tasks, like favoriting a location in the file manager, are nonobvious
  5. Single-click opens files and directories in File Manager, does not open either in the File Browser
  6. The included Music application is awful. Seriously, I could write an entire post about it.

Edit: I actually need to rant about Music. See, it thinks it’s iTunes – which is dire enough, really, but let’s not go there tonight. It’s got the same sidebar-driven UI:


But most of them are superfluous and don’t do anything: clicking on one reports No Songs, and asks the user a bunch of impenetrable nonsense about, uh, editing song rules. Seriously, look:


What are rules? Why doesn’t it have rules already? Why would you give me a sidebar option to list music I’ve never listened to if the player doesn’t know how to do that? Why is this even a feature?

But let’s look at that first screenshot for a second longer. See how I’m almost through the song, and my queue is empty?

Thing is, it’s not. A new song played immediately after that one. Two more have come and gone since I started typing. But still, the queue is empty. Where is this music coming from? If I close the problem, will the queue – which doesn’t exist – empty too? Why did this happen when I pressed the “play” button on my keyboard instead of my Spotify track resuming, and why did the Music application even start in the first place? Actually, let’s get even more basic – why do my MP3s occasionally open in Music, even though Audacious is set to handle MP3s?

Maybe the target user is Mac enthusiasts who wish things just didn’t work so dang much of the time.

Android users, here’s the deal. This is the sales chart of Superbrothers: Sword & Sworcery, one of the best games I’ve played on a mobile device to date:


Source: http://www.swordandsworcery.com/

You will notice that 33% is iOS, and a vanishingly-small 5% is Android. This is because, by and large, Android users do not spend money on software. That isn’t necessarily a piracy issue1: they’re just very used to downloading free stuff.

This isn’t even a port issue2: despite the fact that supporting all Android devices is hard, the Android copy of the game was actually more enjoyable than the iOS version I bought when I went back to iPhone (for unrelated reasons.) Device rotation worked more seamlessly, multitask behavior was more favorable. 3

Obviously, iOS did have an eight-month lead over the Android release, but that doesn’t account for the numbers; indeed, profitable games on Android are still so unusual that it’s newsworthy when it happens.

  1. Frequently piracy is blamed for Android’s persistently-low sales records. The accuracy of this interpretation is up for debate; the sales records themselves, however, are not.  (back)
  2. Where sales of a ported game falter because of issues not present in the original version  (back)
  3. No huge problem on iOS, but fit and finish were definitely lacking.  (back)

I wrote a long and rambling post here about refresh rate, resolution, and animation speed. After nearly a thousand words, I’d worked out all my problems and realized almost none of it was worth talking about. Deleting it was a wrench, but not as much as reading it would have been.

So instead, here’s the conclusions I drew and why, along with a small digression on sprites.


I’ve been working with GLib a fair amount lately for my indie game project. Generally speaking, if you’re doing anything nontrivial in C you’ll be using libraries to provide non-primitive datatypes like hashmaps (think PHP’s arrays) and lists, because while they aren’t particularly complicated problems to solve, there’s no reason to solve them every time you set out to write a program.

This time, I’m using GLib. This is mostly for convenience, because some of the other libraries I’m linking use GLib’s datatypes internally. It’d be kind of dumb to have two or three incompatible list types floating around, after all. For the most part, GLib has made life easy because it’s easy to pick up, because there’s so much code available for study.

One non-obvious problem, though, is iterating through a list of structs. Google was next to useless, with every example broken or irrelevant. The answer’s deceptively simple: you just cast the gList’s data member to the desired type:

int search_foo(STRUCT_FOO *foo) {
  int result;
  GList *search;
  for (
    search = g_list_first(foo->bar); 
    search != NULL; 
    search = g_list_next(search)
    return ((STRUCT_FOO *) search->data)->value;

This is just a simple example, and a pretty simple problem, but it took me an embarrassingly long time to figure out. The cast is mandatory because the compiler doesn’t remember, or care, anything about the target of the pointer you store inside the linked list.

This can also be an insidious source of bugs: if you mistakenly cast the struct as the wrong type, the compiler won’t complain; it may even appear to work correctly, if the data you try to access is simple, like an integer or boolean value.

Notice: The sixsixfive mirror was down for a month or so due to a documentation issue with the TLD authority. Apparently they wanted my actual documentation and not, in fact, some random numbers and letters. I’ve straightened this out and the domain should resolve by some time on November 26th.

More than a decade ago, I started reading a blog called sixsixfive. It wasn’t called a blog, maybe because it was before “blog” was a word. What a sweet, sweet time that was. Anyway.

The author, one Jeffrey S. Power, wrote a list of six hundred and sixty-five different and (quite possibly) interesting things. And that’s pretty accurate, because sometimes he wrote about his life and sometimes he wrote about what would happen if someone undertook the makings of a golem without really understanding the particulars of the process. Sixsixfive was whimsical, light, dark, happy, sad – whatever was going on that day, I guess. To whatever extent these things ever are, online or otherwise, it felt real.

There’s a reason I’m using the past tense: the site is gone. I’m sad about it.


Last time, we talked about what sprites are and how they’re used. Now comes the part where I have to write code for working with sprites, and then explain it.

There are six distinct parts of the process as it concerns us.

Loading sprites into memory

Before we can do anything with sprites, we need the computer to know what the sprite is. It isn’t enough to just have the data saved anywhere – we need to tell the computer how to read that data and what each piece of it means. Inevitably we’ll need to consider the way the actual spritesheet is laid out.

Pictured: NOT ENOUGH.

Banging together a test spriteset was the easy part. Here’s one I made earlier.

There are two fundamental ways to do this: fixed sets, or flexible sets. There are probably official industry terms for this, but I’m self-taught and I don’t know about ‘em.