A small RPG company

Name: Seahorse Adventures
Version: 1.1
Author: philhassey, pekuja, tim, drpetter, and gerry
License: GPLv2
Operating System: Linux, Mac and Windows

Lost Code

The python community had been converting from python 2 to python 3 for over ten years. Starting with Fedora 32, much of the python 2 infrastructure was removed. This included an unmaintained game called Seahorse Adventures. The original developer had moved onto other projects. Without someone stepping up to update the code, it had to be removed.

I did play the game but it didn't have a lot of appeal to me. I believe I even looked at it when it was announced as a package facing removal but decided it seemed like to much work. It still annoyed me to see it removed during upgrade. Despite having other projects to work on I started modifying the game.

Python 3

While I had done some python work, I was not an expert nor had I converted python 2 code before. The print function was my usual check for python 2 vs. 3 code. In python 2, the function didn't need parentheses. Python 3 required the use of parentheses. This game had some calls of print but not a lot.

The first errors encountered were the import statements. With python 2, importing a module would look locally first and then load site packages. This meant that "import data" would import the python data module unless you happened to have a file named data.py. To prevent code from suddenly importing the wrong file, python 3 imported site packages unless you included "from ." before the import.

Errors continued to be encountered with import because not all imports were at the top of the files. A search of code base ensued to fix all the remaining imports.

The next change was easier to search and replace. Python 2 had range and xrange. When converting to python 3, they all become range. At this point the game could run incorrectly.

Seahorse Adventures Screenshot

The last bug affecting Seahorse Adventures was division. In python 2 when you divided two integers, you got an integer. Python 3 changed it to always provide a floating point. Initially I tried to convert as I encountered problems and determined if they were integers or not. In the end I converted every division except for the one or two places that clearly were using floating point. All the other changes were needed because the program crashed. The change to division was harder to fix. I had the game running but I didn't stop there.


Proprietary game services added trophies or achievements some time ago. Even games that weren't connected to a service may support some recognition of events. For example FTL had achievements if you Steam but even if you bought it from GOG it displayed trophies in game. Some players enjoyed these extra challenges. I found it nice to see what games my friends played to determine if anything interested me.

I had pondered how to implement a distributed trophy system for open source games. Instead of having a single service like Steam collecting all game playing information, I wanted people to keep it for themselves or choose who to share it with. This was done with social network through a diverse set of services like Mastadon, GNU Social, Hubzilla, etc.

FreeGameDev forums created a Hubzilla instance which I used. In examining the system, it looked like the plugin system could create the open trophy system I wanted. Shortly after LibrePlanet 2020 I began working on this goal. The system consisted of two parts the Hubzilla plugin and a C library games could use to upload results to Hubzilla. C was chosen because most languages have some way to make use of C libraries.

Since Seahorse Adventures was written in python, I researched several options for interfacing with a C library. I tried CFFI but it gave me an error and I switched to SWIG. SWIG did far more than generate python bindings. It could generate bindings for many languages which could be useful for other games. For the most part SWIG parsed the C function definitions. Including typemaps allowed some arguments to be specified as output so python changes it to be returned by the function.

bool GamerzillaGetTrophy(int game_id, const char *name, bool *OUTPUT);

The function was defined in python as having two parameters and returned a tuple with two parameters, the original return and the result of the last argument.

My initial version proved difficult to use.

seahorse.numTrophy = 1
trophy = gamerzilla.GamerzillaTrophy()
trophy.name = "Defeat Boss"
trophy.desc = "Defeat all levels and boss in order"
trophy.max_progress = 1
trophy.true_image = "data/gamerzilla/win1.png"
trophy.false_image = "data/gamerzilla/win0.png"
trophyArray = gamerzilla.new_GamerzillaTrophyArray(1)
gamerzilla.GamerzillaTrophyArray_setitem(trophyArray, 0, trophy);
seahorse.trophy = trophyArray

You needed to create the GamerzillaTrophy object, set all the fields, and then set it in the GamerzillaTrophyArray. Defining multiple trophies would take a fair amount of code. Instead I created a function to add a trophy

gamerzilla.GamerzillaGameAddTrophy(seahorse, "Defeat Boss",
    "Defeat all levels and boss in order", 14, "data/gamerzilla/win1.png",

The trophies added were just for defeating the three areas and the boss. In most case games included additional awards. For Seahorse Adventures that could be based on number of coins or points or finding a secret area. Seahorse Adventures never set any trophy as completed. Instead it incremented the progress for the trophy. When the progress reached the maximum. it was automatically set to completed.

Trophies Screenshot

No Authentication

The simplest solution would have the user enter their Hubzilla site, username and password but then each game would need to code up the UI for that. Additionally if they would either have to store your password or ask every time you ran the game. Ideally you want some service like the Steam client which handles that for you. Under Linux we have numerous game managers like Lutris, GameHub, etc. We could even store and display the trophy information in a game client without a Hubzilla account if someone was concerned about uploading the data.

Seahorse Adventures assumed that such a service was running. If no such service was running, the trophy information was saved locally and would be synced next time. Since no game manager supported Gamerzilla yet, testing used the gamerzillaserver program included with LibGamerzilla. The server took url, username and password for hubzilla and forwarded updates.

Not Done

Gamerzilla and LibGamerzilla are still in development. The API for game managers is incomplete. Various known issues still exist. Windows has not been tested and may need changes to interprocess communication. The python interface has not been submitted to PyPi. I'm not certain on how that should be submitted yet.

Future work might include a Friendica port if possible or even a standalone trophy server. Most important is game and game manager support. Maybe we can even get commercial developers to add support for the system.


No comments yet.

(optional, e-mail address only visible by admins)

Last modified: 2020-05-05, 08:21

© 2009-2019 Identical Games

powered by phpSQLiteCMS