Joachim Breitner's Homepage

A while ago, I found the nice arcade game Zaz. The goal is to sort rolling marbles by color to make them vanish before they fall down a hole. I enjoyed playing it in turn with my girlfriend, but it was not nice that one of us always had to wait and watch. Also, Zaz is quite hard and my girlfriend (who is better at the game) did not manage to finish all levels. So I thought, that it would be great if we could play the game together! I recently read that the version of the X server on my laptop supports XInput2 and thus multi-pointer-input, so I thought I give it a shot.

The main problem with making the change was SDL, a very common library used by Zaz to interact with the system. The SDL code fetches the events from the X server, handles them (e.g. mapping button presses to unicode characters, remembering mouse positions to calculate relative movement). SDL itself does not know anything about multi-pointers, or the events generated by XInput2. So once I started to listen to XInput2 events, no “regular” events would come through any more and the game stops reacting.

The SDL supports passing unknown X events in a SDL_SysWMEvent. This would have helped, but XInput2 passes its data in X’s new GenericEvents where additional data needs to be fetched with XGetEventData before the next X event is handled. SDL does not know that and thus, when more than one event is waiting, the event data is lost before SDL passed them to the application.

Therefore I completely bypass the SDL event handling and only use XNextEvent myself. This meant re-implementing some logic, especially relative mouse movements and keeping the mouse within the window, guided by the SDL code. I did not worry about text input, so you need to enter the name for the highscore with an unpatched Zaz :-).

The game logic site was surprisingly easy to adjust to more than one player. Just replaced the Player object by an array of Player objects, and the game machinery still works. This is a sign of very good design, kudos to Remigiusz Dybka.

At first, when the laser pointer bonus was picked up, only the first player would get it. I changed that so both players benefit from the bonus. It would make more sense if only the player who actually killed the bonus ball would get it, but that would be hard to track.

In the end, the result is very satisfying. And together, we managed to finish the game at once.

Enough words. Here is a demonstration of us two playing the first level, as a HTLM5 video (alternatively watch it on YouTube):

If you want to try it yourself, you can either grab the Debian packages (v0.2.9, source package and binary built for amd64), the patch against version 0.2.9 or the patch against version 1.0.0. Then you need to plug in two mouses and use the xinput command line program to create a new master and reattach one of the mouses to the second master, before starting the game. And of course, you need a partner (unless you want to play the game bimanually – good luck).

PS: Why is my Ogg/Theroa video, created with recordmydesktop, all green when uploaded to YouTube? I hat to locally convert it to MPEG4 first...

I didn’t want to mess around in the code too much, and I’m not sure if it would actually help in such a fast game – it’s quicker to just wiggle the mouse and see which paddel wiggles. But it would be nice to have.