
In which we take a cool thing and make it weird.
Blast from the Past #
One of my favourite games to come out of the 2014 Global Game Jam was Beholder High, a web-based dating sim set in a high school for beholders.
As the description says:
High school is a confusing time. Especially for beholders. Now the Big Dance is right around the corner, and you don’t have a date! Choose a fellow beholder student and woo them before it’s too late, or the consequences could be dire!
Unfortunately time has passed and you can’t play the game online anymore:

Fortunately, I was talking to a couple of the folks who made the game, and pitched the idea of resurrecting it as an SMS game. They were nice enough to say it was ok, so that’s what I’ll do.
First Things First #
To have something to compare against, I needed to get the original up and running first. It was in PHP, so I set up a nice LAMP server and threw the source on it.

Ah, but it’s looking for http://<hostname>/InTheHighOfTheBeholder/css/style.css
, so I just move
everything under an InTheHighOfTheBeholder
directory, and…

Yay! Part of the problem trying to deploy anyone else’s code is figuring out the setup. Now we have a working instance of the original game to compare against and experiment with.
How does it work? #
/var/www/html/InTheHighOfTheBeholder$ find . -name "*.php" -print | column
./Beth_Fin/02.php ./D1S02/11.php ./Siri_Fin/08.php ./D2S01/day2.php ./D2S03/00.php
./Beth_Fin/01.php ./D1S02/12.php ./Siri_Fin/06.php ./D2S01/06.php ./D2S03/template.php
./Beth_Fin/08.php ./D1S02/06.php ./Siri_Fin/05.php ./D2S01/05.php ./D2S03/04.php
./Beth_Fin/06.php ./D1S02/05.php ./Siri_Fin/03.php ./D2S01/03.php ./D2S03/07.php
./Beth_Fin/05.php ./D1S02/16.php ./Siri_Fin/09.php ./D2S01/00.php ./template.php
./Beth_Fin/Beth_end.php ./D1S02/03.php ./Siri_Fin/00.php ./D2S01/template.php ./Mox_Fin/02.php
./Beth_Fin/03.php ./D1S02/09.php ./Siri_Fin/10.php ./D2S01/04.php ./Mox_Fin/01.php
./Beth_Fin/09.php ./D1S02/00.php ./Siri_Fin/siri_end.php ./D2S01/07.php ./Mox_Fin/08.php
./Beth_Fin/00.php ./D1S02/10.php ./Siri_Fin/template.php ./_index2.php ./Mox_Fin/06.php
./Beth_Fin/10.php ./D1S02/template.php ./Siri_Fin/04.php ./D2S04/02.php ./Mox_Fin/05.php
./Beth_Fin/template.php ./D1S02/13.php ./Siri_Fin/07.php ./D2S04/01.php ./Mox_Fin/03.php
./Beth_Fin/04.php ./D1S02/18.php ./D1S01/02.php ./D2S04/08.php ./Mox_Fin/09.php
./Beth_Fin/07.php ./D1S02/04.php ./D1S01/01.php ./D2S04/06.php ./Mox_Fin/00.php
./index.php ./D1S02/07.php ./D1S01/08.php ./D2S04/05.php ./Mox_Fin/10.php
./D2S02/02.php ./D1S02/14.php ./D1S01/06.php ./D2S04/03.php ./Mox_Fin/template.php
./D2S02/01.php ./bad_end.php ./D1S01/day1.php ./D2S04/00.php ./Mox_Fin/mox_end.php
./D2S02/06.php ./D1S03/02.php ./D1S01/065.php ./D2S04/template.php ./Mox_Fin/04.php
./D2S02/05.php ./D1S03/01.php ./D1S01/05.php ./D2S04/04.php ./Mox_Fin/07.php
./D2S02/03.php ./D1S03/06.php ./D1S01/03.php ./D2S04/07.php ./D3S01/02.php
./D2S02/00.php ./D1S03/test.php ./D1S01/09.php ./template/header.php ./D3S01/01.php
./D2S02/template.php ./D1S03/05.php ./D1S01/00.php ./template/footer.php ./D3S01/03.php
./D2S02/04.php ./D1S03/03.php ./D1S01/10.php ./D2S03/02.php ./D3S01/day3.php
./D1S02/02.php ./D1S03/00.php ./D1S01/template.php ./D2S03/01.php ./D3S01/00.php
./D1S02/01.php ./D1S03/template.php ./D1S01/04.php ./D2S03/08.php ./D3S01/template.php
./D1S02/17.php ./D1S03/04.php ./D1S01/07.php ./D2S03/06.php ./D3S01/04.php
./D1S02/08.php ./D1S03/07.php ./D2S01/02.php ./D2S03/05.php
./D1S02/15.php ./Siri_Fin/02.php ./D2S01/01.php ./D2S03/03.php
./D1S02/19.php ./Siri_Fin/01.php ./D2S01/08.php ./D2S03/09.php
There are a lot of PHP files; one for each possible state in the game. Awkward, but that’s not unusual for Jam games. Now before I write some code to parse through all of these, let’s see if the developer ever went back to refactor the code…
Yes, there’s another repository, where we have:
|
|
A nice big JSON file with all of the narrative logic. Consuming that will be a lot easier than parsing a bunch of PHP files.
Let’s get started #
Since we’re not doing a Jam, let’s put together a somewhat proper TDD environment. To get started with RSpec on Sinatra, I found GetLaura: How to Test a Sinatra app with RSpec to be a good refresher.
A little CI goodness and we’re ready to get started!
|
|
We want to run Rubocop and the Rspec tests, and only fail on an Rspec failure.
First Tests #
|
|
First Code #
|
|
I did have to tweak the JSON file a bit to actually work with this code. Darn initial states and their often being special cases.
First Pass #
After a while:

Now we can get on to implementing the rest. Tomorrow.
Useful Stuff #
- GGJ 2014 Beholder High page
- GetLaura: How to Test a Sinatra app with RSpec
- Giant Robots Smashing into Other Giant Robots: Testing SMS Interactions