April 2014
M T W T F S S
« Mar    
 123456
78910111213
14151617181920
21222324252627
282930  

We hiv a nuu gam and its nim is rafn sun 3D

My parents brought a box of my old school papers and journals and whatnot from their house last weekend, and one of the things in the box was my journal from first grade. I was six. Apparently my parents were letting me play Wolfenstein 3D already. Awesome.

Wolfenstein 3D was released on May 5, 1992 for MS-DOS. I remember playing it, but I didn’t know it was that early in my life. My dad had graph paper with all the levels drawn out. Not too long ago, I downloaded a copy of the game from Steam and was pleased to realize that I still remembered where most of the secrets are. But not all of them – I think it’s time to go do some space bar tapping.

Oh, and in 1995, id Software released the source code. You can get it here.

We hiv a nuu gam and its nim is rafn sun 3d

I think it’s a safe bet that my teacher had no idea what I was talking about. Or is shooting Nazis a typical hobby of first grade teachers?

Registering a .to domain

I was playing with this neat tool for searching for short domain names that was on Hacker News and discovered that the domain name jon.to was available. I figured I’d never come across the opportunity to get jon.anything again for a long time, so I searched for how to go about registering a domain name with the .to TLD since none of the big names seemed to be support it.

I found tonic.to eventually and attempted to register it. They reported that it was taken! At this point, I didn’t know that the whois records of .to domains are rather limited, so I figured that the lack of a record meant that it wasn’t taken. I e-mailed Tonic’s support e-mail, and they promptly replied that the domain was available and they just had to update their records for whatever reason.

So I registered the domain name and waited. After a few days, I e-mailed them and asked why it still wasn’t working. Apparently using afraid.org’s free DNS service triggered their fraud prevention mechanism. They sorted it out for me quickly after I contacted them, although it certainly would have been nice if they had let me know. The person I talked with did tell me to just e-mail him if I ever registered another domain name using the freedns.afraid.org name servers and he would insure that it went through, however. (By the way, if you want a subdomain of jon.to, that’s one of the features provided by afraid.org.)

The next day, I got a phone call from my bank saying there was a suspicious charge to my card from the Kingdom of Tonga. I told them it was okay and then I finally got my domain name. Everything’s set up and working marvelously.

I’m still not sure what to do with the domain name, though. So far I only have a toy project for determining how many of something it takes to reach the moon.

Any ideas for what to do with it?

Also, while purchasing a .to domain turned out to be slightly more involved affair than I’m used to, I ended up a happy customer and recommend tonic.to as a registrar for .to domains. Since none of the big names support the TLD, there are many short domain names still available. I know that when I was searching for available .com domain names for my company, I was becoming increasingly frustrated that I couldn’t even make up a nonsensical word that wasn’t already taken.

We ended up calling ourselves Artful Dodger Software LLC, by the way. Papers were filed with the Secretary of State on February 1st, 2010. I’m attended a new business tax workshop on the 23rd that’s put on by the Oklahoma Tax Commission to try and figure out what we need to do from that perspective. Ergh.

Oh yeah, and the first set of adventures is finally out on Plant Wars. It’s short, but I’m pretty proud of how it turned out. A sequel will be out… some time.

A Dynamic, User-Friendly Captcha With Pictures

When people playing Plant Wars train their characters, they frequently encounter a captcha. This is in order to prevent people playing using an auto-refresher or a more sophisticated bot. Interesting trivia: captcha is an acronym for Completely Automated Public Turing test to tell Computers and Humans Apart.

Originally, I had used reCAPTCHA. I felt good about helping digitize books, and it meant I didn’t have to come up with one on my own. My users, however, did not appreciate having to type two words each time. I do still support the project – for things like commenting or registration, it’s great. For Plant Wars, however, the captcha has to come up pretty frequently and people are lazy.

After this, I tied in the integer that is already being stored in the session to prevent refreshing the fight page to create a new captcha. This required the user to do some simple addition and then click the result in a 3 x 3 grid of numbers. It turns out that people don’t like doing math.

At some point, a user had recommended I take a look at this paper by some people over at Google. They implement a captcha by having a slider bar with a randomly rotated image that the user then has to straighten out using the slider bar. This is really cool, and I use the basic idea but simplified yet further. As I am only trying to protect my game from being able to be played by a program, I don’t have to be quite as rigorous.

Captcha

I opted to instead get three “random” images – these are taken from users’ profile pictures – and flip two of them upside-down. Now, instead of typing anything or doing any sort of math, the user simply has to select a picture. It is a relatively secure captcha that is much more user friendly. Now, I’m aware it has its weaknesses – see the Google paper for details on potential problems/vulnerabilities, but here are a few summarized:

  1. These are user-submitted images. People could start uploading pictures that are already upside-down.
  2. Some pictures don’t have an obvious orientation.
  3. A computer could be taught how to tell what’s up/down in many types of pictures (e.g. blue sky indicates that’s the top).

Now all of these are valid issues and obviously reasons for concern, but I’ve concluded this method is sufficient for my purposes. I do plan, however, to add an “I can’t tell head from tail!” link under each picture which, if clicked a sufficient number of times, would flag that picture as unusable for the captcha.

The response from my users has been entirely positive. They were fed up with the old way of doing things, and this is definitely quick and easy.

Technical Details

When the captcha comes up on the training page, it is generated with this function:


function getCaptcha() {
	$_SESSION["pic"] = rand(1,3);
	$string = '<a href="train2.php?pic=1"><img src="captchapic.php?pic=1" border="0" alt="1" width="200" height="200" /></a>';
	$string .= '<a href="train2.php?pic=2"><img src="captchapic.php?pic=2" border="0" alt="2" width="200" height="200" /></a>';
	$string .= '<a href="train2.php?pic=3"><img src="captchapic.php?pic=3" border="0" alt="3" width="200" height="200" /></a>';
	$string .= '<h2>Click the one that is right side up.</h2>';

	return $string;
}

All this does is store a random number between 1 and 3, inclusive, in the session and then insert three pictures with captchapic.php?pic=X as the source.

In captchapic.php, it finds a random profile picture, and if $_GET["pic"] is not $_SESSION["pic"] then it flips the picture upside down.

Here’s the code for that:


        // getRandomPicture() returns the file name for a random profile picture
	$image = getRandomPicture();

	// Unless $_SESSION["pic"] == $_GET["pic"], turn the picture upside down
	if (isset($_GET["pic"])) {
		if ($_GET["pic"] != $_SESSION["pic"]) {
			$degrees = 180;
		} else {
			$degrees = 0;
		}
	} else {
		$degrees = 0;
	}

	// This sets the image type to .jpg but can be changed to png or gif
	header('Content-type: image/jpeg') ;
	// Create the image
	$source = imagecreatefromjpeg($image) ;
	// Rotate the image
	$rotate = imagerotate($source, $degrees, 0) ;
	// Output the image as a jpg
	imagejpeg($rotate) ;

If anyone has an idea for how to improve it further, please let me know! I’m glad for any and all feedback, and while I’m aware that this approach is far from perfect, my users love it.

Update: It has been pointed out that just by randomly selecting a picture, there would be a 33% success rate. This is true and would be reason for concern if this were a public-facing aspect of the site. Players only see this captcha in-game, however. If a user gets the captcha wrong five times in one day, they are automatically jailed. Would I ever replace the conventional captcha for commenting on the blog with it? No. But it works well in particular circumstances where your priorities are to keep your users happy first, and honest second. Also, if you need a lower percentage, you can always just add more pictures.

Word wrapping, JavaScript vs CSS

Here’s the scenario:

You have some content that you’re pulling from a database. It’s user-generated, so you have no guarantee that it makes sense. That means that people could fill up all the allowed characters without entering any spaces, insert quotation marks and apostrophes, and anything else. Now, you want to display this data in, say, a table with a fixed width.

We want to make the words wrap. We don’t want to overflow the container, and we’d prefer not to hide the text.

If all your users are using IE, then you’re in luck: use the CSS “word-wrap: break-word” (or if you have a browser from the future, when CSS3 will have this and more). If not, we have to make a choice.

If you absolutely need word wrapping, here is what I’ve come up with. It’s definitely clunky, and I’d love to see a better solution. It does, however, work. I would not recommend using this method on a large string, as the user may see a hit in performance.


<span id="text" style="display: none">your-possibly-really-long-string-goes-here</span>

<script type="text/javascript" language="javascript">
	var string = document.getElementById('text').innerHTML;
	var stringWords = string.split(' ');
	for (var i = 0; i < stringWords.length; i++) {
		if (stringWords[i].length > 20) {
			stringWords[i] = stringWords[i].split('').join('<wbr />');
		}
	}
	string = stringWords.join(' ');
	document.write(string);
</script>

The JavaScript splits the string into words (strings separated by spaces), and then for any word that is longer than 20 characters, it inserts <wbr /> after each character. By limiting this to long words, you won’t be splitting short words in awkward places. The wbr (Word BReak) tag inserts a soft line break. In other words, if the text would overflow the container otherwise, a line break will be inserted. For more useful information and for comparison of wbr, & shy;­, and & #8203;​ see this site.

To make the wbr tag compatible with Opera, you’ll need to add this bit of CSS:

wbr { display: inline-block; }

I tested with Safari 4, Firefox 3.0.10, IE 6, Opera, and Chrome with no problems.

If, however, you do not need word-wrapping, life is much simpler. The CSS property “overflow” is all you need to prevent text from overflowing its container. Put it in a div and give it a bit of CSS. You have several choices, but only two of them matter.

By specifying “overflow: hidden”, all text that would have overflowed the contained is, well, hidden. It’s truncated. Any strings that are ridiculously long probably aren’t valuable, so why not?

The other choice is “overflow: auto”, which will give the div a scroll bar if its contents are trying to over flow it.

If you have a better solution to this problem, please let me know. I’m really looking forward to CSS3.

Snow Dragon: Part 2. Now with more baby!

Part one is here.

Snow Dragon

See part two here!

Here’s what I did with my afternoon.

Face

Alex helps

Alex helps out. Great pants, eh?

Snow Dragon

Snow Dragon 3

Snow Dragon 4

Snow Dragon 5

Snow Dragon 6

Plant Wars: Development Postmortem

I was recently asked to write a postmortem (it’s sort of a “lessons learned” from the development process) for Plant Wars for Building Browsergames, and I just finished, so I thought I would share it here in its entirety:

This is Jon from Plant Wars, which is yet another PBBG (what else would I be doing here?). I started the game around 9 months ago as I was searching for a job after graduating with a bachelor’s in Computer Science. I had only learned a minimal amount of PHP for a class project earlier in the year, so I definitely have used the process as a learning experience. Still, I’m pretty sure I can tell you more about what not to do than what to do. As with any web-based game, we are constantly developing and are far from being done.

First of all, set up a test site with its own test database. Keep it up to date so that you’re not tempted to cheat and just make this tiny change on the live site first. I cheated when I implemented the password change feature. The query it used when someone changed his password was “UPDATE Users SET Password=md5($newpassword)”. Notice something missing? That “WHERE Id=$_SESSION["Id"]” clause is just so easy to forget. That was a mess that would have been worth any level of inconvenience in maintaining the test site to avoid.

Secondly, I’d recommend using a framework, such as the Zend Framework for PHP. This is because I didn’t and still don’t. I don’t even have data access objects. Sure, I store some commonly used methods in files that I include on every page. Alas, I’m still in the habit of embedding queries in the pages directly. Separation of logic and presentation? Yeah, that’d be nice.. At my day job, I use the Struts framework with Java – and while it does make the initial development take somewhat longer in the case of Struts, it is definitely worth it. The maintainability is increased incredibly by the proper separation of concerns. Once you learn a framework, you should generally find that your productivity increases. The initial learning curve is worth the sacrifice at the beginning for the long term benefit.

Perhaps the most important thing I did right was to have my friend Daniel help me out whenever possible. Going at such an endless project alone is intimidating, and having someone else to shoulder some of the burden is essential. Coming home and seeing a new feature implemented that you didn’t have to lift a finger for is exhilarating. Plus, then you have someone to brainstorm with and to just talk with about the game. Your girlfriend (or mom, if that’s the case) may pretend to care, but she’s probably tired of hearing about it.

In the same vein, it’s essential to have some trustworthy staff members. Grant these people moderation powers on your game’s forum and give them the ability to check the logs for cheaters. Write a nice administration panel for them (and yourself) that will streamline the process of checking for cheaters. For example, one button click to see all users who have shared an IP address. Examining log files may be your thing, but it’s time that you should be spending developing. Ensure that your staff is – once again for emphasis – trustworthy, as well as good role models for your community.

If you have staff that you don’t know personally help on the site’s development, don’t give them access to the live database. Restrict them to the test site – another good reason for its existence. Merge their code yourself. I made the mistake of granting access to the live database to my first staff member. I got off easy when he just made a page to bump his stats up artificially.

My final recommendation is regarding monetization: if you would like to at least make enough cash to pay for your hosting costs (which we usually manage – if barely), ensure that people can donate for some advantage in your game. For example, with Plant Wars, donors gain fertilizer (which is spent to train, fight, etc) at twice the rate of non-donors. I charge a low price of $2/month, and I’m not sure if I would recommend going that low. My initial price was $5 and that received lots of complaints and no donors, but now that the game has progressed, I’m more inclined to believe that anyone who donates currently would be inclined to do so even if it were a couple bucks more expensive. Use your best judgment. Also, I allow anything that can be bought with real money to be sold player-to-player so that a) there is more motivation for people to give me real money and b) people who can’t give real money still have the opportunity to gain the same benefits with increased activity.

People hate clicking on ads. It is worth the minimal time investment necessary to sign up with some sort of pay-per-action network, such as CPALead (disclosure: referral link). This allows players to fill out an obnoxious survey for an in-game reward, while you get some money.

Come check out the Plant Wars blog and you can also follow us on Twitter! (As a related, post-final recommendation, open up communications from your game as much as possible. It increases the likelihood that someone will find you from a social networking site or a search engine.)

Girl throws rock, busts guy’s head open [bloody, probably nsfw]

This is an old video of mine, and it’s off topic for this blog, but I thought I’d go ahead and share it.

We were hitting golf balls in the woods behind my parents’ house, when Rock (yes, that’s his real name) started teasing Eva. She retaliated by throwing rocks at him. The last one connected, which just happened to be the largest of the bunch.

We pick up our friend Drew at the end on the way to the hospital, and his remarks really make the video. Be sure to watch ’till the end. If I remember correctly, Rock ended up getting 7 stitches.

Plant Wars: The Facebook Rip Off (Also: Hobowars vs Buskerwars)

So a few months ago, this guy named Oli joined Plant Wars. I noticed that he had a Buskerwars e-mail address, so I asked him if he was a developer on that project. He said he was, and we had a friendly chat about game development. Busker, by the way, is a British word for a street performer.

It should be noted here that Buskerwars is a clone derivative from Hobowars. It’s been changed around some, everything is awfully similar. Even the terms of service: see here and here. To give more damning evidence, compare the screen shots of the Hobowars’ city with Buskerwars’ town:

Hobowars' City

Hobowars' City

Now make sure to note the remarkable similarities; the introductory texts’ differences are particularly amusing:

Buskerwars' Town

Buskerwars' Town

You can see that there are certainly different (or at least renamed) areas of the games, but the similarities are undeniable.

Anyway, the above was just to establish the background of the guys who ripped off Plant Wars. He copied all images from plantwars.com – from the main, large logo on the log in page, to the images of the various types of plants, to the weapons and armor pictures. These were all created specifically for plantwars.com and were original artwork.

To give a simple illustration on how he based his work on mine – and then, yes, admittedly, added improvements, let’s look at some screenshots again.

First, the original:

Plant Wars Fertilize Page

Plant Wars Fertilize Page

And now here’s the Facebook version:

Facebook Rip Off Grow Page

Facebook Rip Off Grow Page

Did he improve on the design some? Sure. Add some nice things like the graphical bars indicating how full your fertilizer (“energy”) is? Sure. Is it a copy of my work? Sure looks like it to me. And then he slapped a bunch of ads all over it (we just have one nondescript AdSense bar at the bottom of our pages if you’re not a donator).

If anyone would like more screenshots, I have some.

The story does have a happy ending though – Plant Wars on Facebook is no more. While Facebook did not respond when I reported the application as infringing upon copyright, they took the clone offline very quickly when it started spamming ALL the friends of anyone who added it. Check out the usage statistics from AllFacebook:

facebookstats

The application went from 124 active users on February 22 to 23,685 on February 25. Spamming does, apparently, work. Horrifically effective results, and it really makes me wish I knew just how much spam the application sent out. Absolutely ridiculous, and sort of amazing.

On February 26, the Facebook Plant Wars had zero users – because it no longer was available on the platform. Spamming is a much more efficient way to get Facebook to kick you off than having someone complain that you stole all their stuff, apparently. On February 25, plantwars.com had 232 new users register (compared to the average of around 10 a day). While I wish more had come over, it was certainly a perk.

This has motivated me to get a couple of books on developing for the Facebook Platform, however, to try and save our reputation on the site. The inherent viral marketing that goes along with it would be nice as well (as all friends of an individual are notified when he adds a new application, for example).

There are at least five anti-Plant Wars groups on Facebook, although most of them are in Italian (such as “Un grandissimo fanculo a plantwars,” which translates to “A big fuck to plantwars”). It wasn’t us, guys, promise!

MySQL Date Functions and Determining if a User is Active

I learn something every time I look at the MySQL Reference Manual: Date and Time Functions.  I should really look at it more often.

Too often – always – I do not have enough time to spend time adding new features to Plant Wars.  Between having a full time day job and a baby at home, I’m a little pressed for time. That means that as soon as I come up with a way to do something, I hit the ground running. This means I typically end up with very sub-optimal solutions.

As a rather embarrassing example, consult the following code snippet I was using to determine if a user had been active in the past 10 minutes. Any time a user is active, the LastActive attribute in the Users table is updated. Here, this value has been stored in the $lastActive variable.


$lastActive = explode(" ", $lastActive);
$date = explode("-", $lastActive[0]);
$time = explode(":", $lastActive[1]);
$online = false;
if (date("d") == $date[2] && date("m") == $date[1] && date("Y") == $date[0]) { // user was active today
   if (date("H") == $time[0] && date("i") <= $time[1]+10) { // user was active in last 10 minutes - MODIFY TO CHECK IF USER WAS ACTIVE IN LAST 10 MINUTES EVEN THOUGH IT WAS THE PREVIOUS HOUR OF THE DAY
      $online = true;
   }
}

As you can see, even doing it in this ridiculously drawn out way, it still would mess up if, for example, a user had been inactive at 4:59 and it is now 5:01.

After consulting the MySQL date functions again, I have come up with a much more eloquent (and sensible) solution:


	$query = "SELECT *, NOW()<DATE_ADD(LastActive, INTERVAL 10 MINUTE) AS Active FROM Users WHERE Id='".$id."'";
	$result = mysql_query($query);
	$row = mysql_fetch_assoc($result);

Now to test if a user has been active in the past 10 minutes, I just check if ($row["Active"]).

To explain, NOW() returns the current date and time. DATE_ADD(date, INTERVAL expression unit) adds the specified amount to the date. Don’t use plural units (MINUTE is correct, MINUTES is not).

To summarize, it is best to do your research into the capabilities your available tools, as it will often save you time, make your application faster, your code more readable, and just generally be a better solution.

Update 3/3/2009

As wwosik pointed out on reddit, this is an acceptable solution for determining if a single user has been active in the past 10 minutes. But what if you want to find all active users? It is costly to have MySQL execute the date functions for every row when it is unnecessary.

To solve this problem, we need to calculate the date/time 10 minutes in the past and then we can just store this value and compare the LastActive attribute of each row to it, without needing to calculate it for every user.

To do this, I use the mktime() and date() functions.


// int mktime ([ int $hour= date("H") [, int $minute= date("i") [, int $second= date("s") [, int $month= date("n") [, int $day= date("j") [, int $year= date("Y") [, int $is_dst= -1 ]]]]]]] )
$activeThresholdUnix = mktime(date("H"), date("i")-10, date("s"), date("m"), date("d"), date("Y"));
// Since mktime returns the Unix timestamp, we need to convert it into something comparable with the SQL timestamp
$activeThreshold = date("Y-m-d H:i:s", $activeThresholdUnix);
$query = "SELECT Id, Name, Level FROM Users WHERE LastActive>'".$activeThreshold."' ORDER BY Level DESC";

There is probably a better way to calculate the time 10 minutes ago, but this is certainly a step in the right direction; it is much more efficient than performing unnecessary calculations for every row.