A New (sorta) Project

I’m in a few online communities. Shocker, I know.

Some of the communities are tight-knit, some are looser-knit, some are very casual.

In one of the communities I’m in, one of the folks there decided to throw a trivia event. Now, I love trivia (obviously) and I love the subject matter of that community, so I was like HELL YES.

And it was done quite well, except that the host’s wife ended up manually tabulating the results of like 30+ people across five rounds.

So, I said to myself, that if the host wanted to do this again, I would offer my LEET SKILLZORZ.

And a new trivia date (later next month) is happening, so I’m helping out!

How? Basically, I’m taking Challenge 1 – The Rapids from River of Kurn and I’m repurposing a lot of code.

Something I wrote is actually going to be useful for something other than its original intended purpose??? What?!

Since it’s so low-stakes, I’m playing fast and loose with a few things. First, there’s only a login if you’re an admin (so me and the host) and everyone else just picks their username and it populates the table with that username and a whole bunch of null values across the table. I probably don’t need to run a unique check (although the value should be, you know, unique in the database) because most people use their regular handles. See, fast and loose. hahaha.

So how it works is that you “log in” by entering your name. Your name gets put into the database. All the columns are populated with null. Each column represents a specific question in a specific round of the game. Five rounds, ten questions each. Now, the host does not want people to know their score, but if we’re going to prevent the host’s wife from manually tabulating All The Things, then the game needs to know the score and store that (as well as the answers) to present the host’s wife with a list of “okay, this is what everyone wrote for round 1”. Then the host’s wife can go through and manually grant “correct” if the game was like “nope” but it’s close enough. There shouldn’t be too many corrections, but it’ll be nice that a human will look it over.

So logging in as the host or me will get to the admin page where you can pull up round 1, 2, 3, 4 or 5’s full answers and make modifications and then also have a scores page which will list scores in descending order from highest to lowest, linked to the username.

Meanwhile, users will only move into each round (which is timed!) when the host tells them to. The form won’t show any questions, only fields for answers. The post data gets carried to a calculate page where the answers are stored and the score is calculated and stored. Then the users get brought to an “in between rounds” page before they are instructed by the host to move forward by clicking a link. Each answer page will be timed and the form will autosubmit when the time runs out, much like The Rapids. Only the host is much nicer than I am and will grant several minutes instead of one minute to answer these trivia questions. It makes me feel like a somewhat evil, maniacal game designer. And I gotta say, I don’t hate that feeling. ;)

So I’m playing around with all kinds of stuff right now and it’s fascinating how much I’ve forgotten about, say, a login process. My login process for River of Kurn is awesome! It’s smart, clever, logical, commented and, honestly, I’m impressed with myself from two years ago.

I’m also remembering that being able to process form data makes me feel like a god.

You can do anything when someone submits a form. Like seriously, damn near anything you want. Want people to go to THAT page when you’re done? Sure. Want them to see THIS message? Okay! It’s a lot of fun to play around with things that are slightly (okay, quite) different from my game and still manage to modify my own code to make it work for this purpose.

In terms of River of Kurn, things are progressing. My current goal is to stop using a MySQL docker container to hold my database when, you know, I can use an Amazon RDS server. So that’s the project for this weekend and next. It should theoretically be okay, but I’m having to look into CICD stuff (continuous integration/continuous deployment) because if I’m going to use an RDS stage server, I’m going to have to change things when pushing to master and deploying to production or my code will just point to the stage server. So that’s a whole other headache to deal with.

This is why I’m cool with tinkering with this trivia game project before getting back to River of Kurn. At least I have the foggiest notion of what I’m doing with the game project as opposed to the devops side of things with River of Kurn.

Anyway. Quarantine/self-isolation continues to ensure I don’t get this nasty virus out there. I hope you and yours are all safe and healthy.

Released The Rapids!

I started work on the first challenge in my game, The Rapids, on March 8.

That day of work included the creation of two files and the modification of two other files.

At least 100 hours of work later, I have a challenge. And it, you know, works. And people can’t cheat! (Well, I’ll say that they probably can’t easily cheat because I probably haven’t fixed every possible way to cheat, but I did a lot to try to prevent it!)

If I didn’t care about people cheating, I would have had it much easier. The issue here is that people are playing in a web browser. They’re not playing in an environment that I can tightly control, like an app on the phone or an actual application you run on the computer. The text-based games on Bulletin Board Systems, like Legend of the Red Dragon and Trade Wars 2002 and Sky Mountain never had to contend with back buttons and reloading. It’s making me wonder how easily I could port this to an iOS game. I’m pretty sure the answer to that is “not easily”, but it certainly bears more investigation. Any kind of app is probably something to look at for another game in the future, rather than for this one.

As such, I have to bear in mind that the back button and reloading are things that can happen and so I have to account for them.

So the first challenge is implemented and works. Failure has the right results and so do the varying levels of success. And I even partially rewrote my maintenance script so that everything that has to be reset at maintenance does get reset. (And it should be easier to implement more maintenance events going forward.)

More than two months after starting it, I’m basically done. There are a couple of tweaks to make, such as a nicer transition from the normal paddling to the challenge stuff, but that’s… it’s not even secondary at this point, it’s tertiary.

And so now, what do I turn my attention to?

There’s the obvious: the second challenge. But I also have more than 50 open issues in my GitHub repo and should, you know, start looking at those things. I also want to bring the currency (Fire Opals) into the game with more regularity than just doing well in the first challenge. And… and… and… The list never stops.

So rather than think about the literal dozens of things I could do, I spent a few hours on Monday thinking about the second challenge.

Part of my problem here is that I like the idea of a river. And so any obstacles necessarily have to be water-based. And, for best results in terms of believability, should be things you’d encounter on a river.

So the first is The Rapids, mostly based on the rapids up near my parents’ cottage in the Laurentians. Like, that particular set of rapids is what I think of when I’m thinking of the rapids in my game. It was pretty easy for me to say that the key to the challenge about rapids would be answering questions quickly. It just makes sense.

In thinking of these challenges, I also decided that the third and final challenge should be a waterfall. Let’s ignore the fact that I have no idea (yet) how that translates into gameplay.

But I was stuck on the second challenge and only sort of came up with a half-assed idea of a whirlpool. Why? Well, it’s a water hazard that people can easily visualize. How would it play, though? So I spent some time brainstorming and researching and I think I’ve figured it out.

A whirlpool can easily mix things up. It can also pull in nearby items, objects, debris, that sort of thing. So I’m thinking that it’ll be some challenge-specific categories (unlike the first challenge, which draws on the regular categories and questions) that will be all mixed up together, and then, in terms of debris, it’ll be multiple choice, with one right answer and multiple wrong answers. In this way, it’ll be a bit easier, which should mitigate the fact that you’re not choosing your category, like you can with the first challenge.

And, like the prior challenge, very similar (if not identical) rewards. Oh, and it won’t be timed.

So, what’s next? Probably a small release dealing with a couple of small fixes/enhancements, followed by the second challenge. The good part about the second challenge is that most of the database is set up for it already, and I already have a good idea of how to prevent cheating based on the first challenge, so I shouldn’t need two months to get it done. Maybe the end of June is feasible? We’ll see.

In the meantime, all existing users who have completed the intro (and then all subsequent users who complete the intro) will begin at 475km in order to better be able to hit the first challenge at (around) 500km.

Have you tried it out? If not, what are you waiting for?

https://www.riverofkurn.com/

Hope to see you out there on the river!

Brilliance, Stupidity, Scope Creep and More

One of the most interesting things to me about this game project is that I am constantly astonished by myself because I was either really smart about something or really stupid about something.

For example, I’ve been working on the rewards for the first challenge and I realized that I was really smart in terms of how I charge my user energy for paddling down the river. I only charge them for it once they answer the question, one way or another. So in building a way to skip a question at no extra cost (but no forward movement), I was like… oh, so I can just generate the new question without including the trigger to charge them until they answer the newly-generated question! Sweet!

(We shall ignore the moment of late-night panic when my brain screeched to a halt and was like WAIT SHOULD THEY EVEN BE CHARGED HERE???? and thank my friend Lisa who helped me logic my way through things at 3am to realize I was, in fact, correct.)

Then, though, then I am faced with my absolutely terrible forward planning skills when it comes to my maintenance routine. Because, you know, I now need to add several changes to the maintenance routine to accommodate the changes brought on by the first challenge. (All the rewards are done, victory stuff is working fine, and even failure stuff is fine. It’s just maintenance that’s killing me now.)

So the main issue is that my original maintenance routine was written, uh, late last August or early September. I was eager to get things working because I wanted to launch the game and maintenance was one of the last things I needed to work on.

Presently, it works via bash script which is automated by a cronjob. So at 07:00 UTC every day it:

  • runs Green Game maintenance
  • runs Blue Game maintenance
  • does a database dump
  • uploads the database backup to the S3 bucket

The problem is how it runs Green and Blue maintenances. It just runs these two .php files, each of which define some variables that are specific to the game, and then runs the runMaintenance() function with those variables. In theory, this is super clever. In actuality, the positioning of the files, in order to not make them accessible via the web, confuses matters.

Even apart from that, my runMaintenance() function is also a nightmare because it’s got about 13 function calls within it. So I’m legitimately thinking about ripping out maintenance entirely and starting from scratch, all because it’s just too janky for my liking.

Scope creep is also real and annoying. I have to find a way to add more Fire Opals to the game and not just as a reward for doing well in the first challenge. But I also want the first challenge to be your introduction to them, so I’m going to need to insert random events to come across them if your location is greater than 500km.

Speaking of scope creep, I have to do the same with the companion for your travels, in addition to deciding when the companion decides to leave you.

I’ve rescheduled a potential launch no less than four times in the last month. I am determined to do it this weekend. It’s just going to be a long week before I get there.

Oh, and as to my ponderings about spelling and stuff, I’m going to implement a similarity match of about 90% just on the challenge page to start and we’ll see how that goes. If it goes well, I’ll expand it to the rest of the game. If it doesn’t, I’ll retool it. I’m also going to have Dorene tell you that you spelled it wrong and what the actual spelling is. However, there won’t be any bonuses for someone spelling it perfectly, nor will there be any downside to spelling it wrong (within that ~10% margin of error). More stuff to code if it goes well in the challenge.

It just never ends. Here’s hoping that whatever I come up with for maintenance is less janky and more reliable going forward so that I don’t want to throw the computer out the window when I have to modify it to include the second challenge stuff.

String Comparisons vs. Fuzzy Matching

A friend of mine finally started playing my game this weekend. I’d sent out a general email to a bunch of my friends last September and most of them played around a bit. This particular friend decided to look at it this past weekend and boy did she have some comments!

I have like seven emails from her with various complaints, ranging from what the hell to this is the correct answer to implement a spellcheck.

While I argue that someone who is as much of a Star Wars fan as she is (PS: May the Fourth be with you!) should be able to spell Alderaan, I do admit that the strict comparison I currently perform in the game is a little, how shall I put this, unyielding.

Look, I’ve always been a good speller. I know which to/too/two to use. I know how to spell antidisestablishmentarianism. I know how to spell supercalifragilisticexialidocious. I often take it for granted that other people can, or perhaps should, spell things properly.

So when I was writing the early code for my game, I was like, yes, sure, let’s do a strict string comparison on the submitted answer and compare it with the correct answer and the alternate answer.

At the time, I knew that it would be unforgiving and I thought to myself meh, I’ll worry about that later.

So with my friend having written me several emails to complain, I figure that now is later.

As such, rather than do any of the things I desperately have to do in order to finish up the first challenge, I spent any time coding this weekend on researching fuzzy matching in PHP.

There are apparently four ways to do this. The one that looks the absolute easiest is the similar_text() function. You can use it to compare one thing to another and it’ll give you a percentage of how much it matches. So, for example, if I have “Beverly” as the answer to a Star Trek: The Next Generation question, but someone answers “Beverley”, I can do this:

similar_text(“beverley”, “beverly”, $percent);

echo $percent;

And that gives you 93.333333 (repeating, of course).

So that means that the user-submitted string of “beverley” is a 93.33% match to the actual correct answer of “beverly”.

Using this, I can set an appropriate percentage limit to grant a correct answer. So like, if the limit is 93% or under, then “beverley” will match “beverly” and will get the question correct.

HOWEVER.

A lot of this works on length. So while adding an extra letter to Beverly isn’t a big deal, what about Data’s cat, Spot? If we’re looking for “spot” as an answer, what if someone adds an S and says “spots”? It’s a shorter word, so that only gives an 88.88888% (repeating) match. Should be simple, right? Just set the limit to 90ish percent and we’re good, right?

Well, what if it’s a Red Dwarf question and I’m looking for the answer is “dave” but someone submits “david”? Again, since it’s such a short word and because two letters are different (the e replaced for the i and the d added), this is only a 66.66666% (repeating) match. Shouldn’t someone who types in “david” get points for “dave”?

What about the poor person who typos dave as save? There’s one letter different and so this gives a flat 75% percentage match. While I would argue that save does not equal dave in the least, the S and the D are right next to one another.

What about things that are very similar and yet different? Say I’m looking for ursa major as an answer and someone types in ursa minor. That’s an 80% match. So maybe the match criteria needs to be higher than 80%. But where does that leave us with Dave vs. David, or Dave vs. Save?

Even aside from “what should the limit be”, I’m now also thinking about whether or not there’s a notice to the user that “mmm, that’s not quite right, but I’ll accept it” and then show them the correct answers. Does it matter if someone spells it Beverley if they get it right? Does it matter if they eventually learn that it’s Beverly? How important is that knowledge if it doesn’t do anything different in the game?

And then, of course, one has to think about whether or not properly spelling something should be an advantage in the game. Should I go farther if I can spell Beverly right as compared to Beverley? Maybe I could show a notice saying “mmmm, I’ll accept it, but you’ll only go half as far for this one” and then divide by two and round down to the nearest whole number (unless the number is zero, in which case it would become one).

But does that unfairly reward the good speller? What if I do show the proper spelling, which then gives someone the chance to improve next time?

One of the most fascinating parts of game design, to me, is the question of “sure, I can do it, but should I?”. That question has been a constant presence in the back of my mind since I started out on this project. I can do just about anything. But I’m coming at this from my own biases and perspectives, obviously. As someone who is a good speller, it’s only natural to me that I would want to be rewarded for that. But if I were a terrible speller, I think it would suck to only get a portion of what a good speller gets.

Food for thought!

Rewards

I eventually solved the problem I outlined in my previous post, though I’m still not fully satisfied with it. I wanted a really kind of random ordering to my questions but because MySQL returns them in ascending primary key order (which, in this case, is the question_id), there’s no good way to consistently serve them up in the same random order. So, fine, okay. The questions are still randomly selected, more or less, and then displayed in order according to question_id. Fine. I can live with that, even if I don’t love it.

So I got that working, uh, April … 19? So like, the day after my last entry. It wasn’t particularly hard so much as it was annoying. And it’s still somewhat annoying. But I’ll live.

What hung me up for a full week was what came next:

What to reward the player with after they pass the challenge?

For real, I was stumped.

I have no idea
Sabrina the Teenage Witch doesn’t know, why should I?

So I thought about it. A lot. And I watched a lot of YouTube videos of game designers talking about things. They talked about being generous, they talked about player psychology, they talked about extrinsic and intrinsic motivation…

I finally did a real brainstorm. Like an honest-to-god, old-school brainstorm, the likes of which I rarely have done outside of elementary school, where I just wrote down everything I could think of on various pieces of paper. And this was the result.

The contents of my brain.

Then, as if things weren’t tough enough, I also wanted a graduated reward system.

Let’s be honest, I’m asking people to answer 10 questions correctly in 60 seconds — including spelling. Even if you’re picking a category you’re super familiar with, you may not get all ten. In my testing, I usually got around 8/10 for most categories and I wrote the damn questions.

So I wanted to balance for the likelihood that people who pass the challenge get 6-8 questions right and if they get 9 or even 10, they should get something awesome.

Here’s how that turned out.

5 questions or fewer correct: BZZT! Sorry, please try again tomorrow.

6 questions correct:

  • Visit from the Wise Water Spirit to encourage them
  • Replenishment of energy
  • The ability to continue down the river

7 or 8 questions correct:

  • All of the above, plus…
  • Moving a distance down the river, courtesy of the Wise Water Spirit

9 questions correct:

  • All of the above, plus…
  • Three Fire Opals. I won’t go into what these do specifically, but they’ll be a form of currency.

10 questions correct:

  • All of the above, plus…
  • A companion for your travels!

Listen, I was heavily influenced by the BBS games of my youth, okay? When I thought about my favourite moments from Legend of the Red Dragon, I thought about getting a horse that would extend your day. So I decided to incorporate a (temporary) companion for your travels if you manage to get ten questions right. The companion is a large turtle (tortoise? I’m calling it a turtle.) and will make your journey down the river more expeditious, shall we say. That said, at maintenance, the turtle can decide to leave you and go on his merry way. There will be a maximum number of days the turtle will accompany you, too.

The most fun bit is that, back in Grade 8, me and three of the girls in my class at school decided to get turtles and we’d take care of them in the school’s bio lab. My friend, V, named hers Tiny, I named mine Wriggles, another girl, J, named hers Hugo, and then F brought one of her turtles from home whose name was Ribbit.

There’s a very long story here in which J’s friend (and my future best friend, but I definitely didn’t like her at first), nearly killed all the turtles by mistake, but, frankly, that’s a story for another time…

Anyway, I decided that if I was adding a turtle, by golly, that turtle will have a name and there’s a random chance that its name will be either Tiny, Wriggles, Hugo or Ribbit. I’m ridiculously pleased by this. Not only am I adding something cool, but it’s meaningful to me personally because of the names and because of the concept coming from the coolest event in that old BBS game.

So I spent a lot of time modifying the database to ensure that it could handle all the things I needed to add — turtle stuff, Fire Opal stuff… Then, I had to start writing functions to ensure that the database changes happen based on the score you get. So I got that bit done tonight and then I got to start writing the encounter with the Wise Water Spirit, depending on your score, and did that tonight, too.

My code works, my text works (I used switch statements both for the code and for the text) and really, all that’s left is:

  • make sure you can’t do the rapids again once you’ve done them
  • add tasks to maintenance, such as turtle stuff
  • make sure I offer the right options to players based on them passing or failing the challenge
  • make sure I edit things to incorporate the possibility of a turtle and/or Fire Opals

Once I do all that (mayyyyybe on the weekend???), then I’ll be in good shape to actually launch the challenge. It’s gonna take a couple of hours to launch, for sure, because I have a lot of things to do to the database. Everything from adding category ID numbers (and adding 100 questions about Survivor!) to all the challenge-related tables. So much to do there, so there will certainly be some maintenance first, but we’re definitely getting close to the launch of the first challenge.

I suppose I should really start thinking about the second challenge… Oh boy.

Anyway, I should get some sleep. Hope you and yours are staying safe during this time!

The Rapids are Going Slowly

By which I mean my work on Challenge 1: The Rapids, is going very slowly. The rapids are, by nature, quite quick…

So the goal here is to present players with a challenge that they must pass in order to continue on their way down the river. My challenge of choice is for them to pick one of five categories, which are randomly selected. Then, once they pick a category they want, they get ten randomly selected questions from that category.

In theory, all of this works beautifully.

It’s when you want to prevent cheating that things go to hell.

If I could count on no one hitting the back button or no one reloading, then things would be fine. But because I’m not in an app, I can’t control people’s actions, so I have to account for the possibility of rampant cheating.

So I’m locking the category choices. Once shown to the user, they get saved to the database. And once you choose one of them, that’s also saved. And then the ten questions that get randomly selected? Also saved. (And then, because I’m not an utter monster, they will all get wiped at maintenance if you fail the challenge, so that if you had a bad day, you can come back fresh the next day. And this also prevents cheating because you can’t then go look up the answer.)

I’m taking the ten question IDs and storing them, then retrieving them.

The problem is that I’m then retrieving the question details (question, answer, alt answer, etc) from those IDs and they are all coming back in ascending numerical order. This means that when you first look at the questions, they’re in the order in which they were generated and passed back to that page. So, basically:

CHALLENGE PAGE: “Yo, Function, get me ten questions from Star Trek: The Next Generation!”
FUNCTION: “You got it! Okay, get all the questions from Star Trek: The Next Generation. Then, shuffle them. Then, slice off the last ten of them. Then shuffle them again, for funsies. Yo! Challenge page! Coming back at you!”
CHALLENGE PAGE: “Thanks, Function!”

So all of that works. But if these values are locked, this is what happens:

CHALLENGE PAGE: “Yo, Function! Get me the the saved question IDs for this user!”
FUNCTION: “Sure thing! Here you go, there’s ten of them!”
CHALLENGE PAGE: “Awesome, thanks! Now, can you get me the questions for these ten question IDs?”
FUNCTION: “Yep! One sec! Okay, get me all the data for any question matching these ten question IDs! Great. Yo, Challenge Page! Here we go!”
CHALLENGE PAGE: “Thanks! … wait. This… this isn’t the same order, is it?”
FUNCTION: “You never said it had to be the same order.”
CHALLENGE PAGE: “That’s implied, jerk.”
FUNCTION: “IS IT CODED THAT WAY? NO? Then just be glad you’re getting that info, buddy.”
CHALLENGE PAGE: “COME ON, seriously?!”

Pulling the question data based on the submitted question IDs pulls the questions in ascending numerical order by question ID. Even if the question IDs weren’t passed along in that order.

So this leaves me with mismatched questions and answers on any potential reload or revisit of the page. Again, if they don’t try to reload or change categories or questions, everything is fine, but if they do that and then attempt to come back to the challenge page? They can’t possibly win because everything is out of order.

I have three potential solutions and I hate them all.

  1. Store the question ID AND the question itself when locking the questions. Why do I hate this? Because it’s lazy and yet still a lot of work.
  2. When locking the question data, order things in ascending numerical order (and also define that precisely when retrieving the data). I hate this because I don’t want my questions in ascending numerical order. I suppose I could do that and then shuffle things. I guess.
  3. Make sure I’m retrieving the question ID with the question data and redo the question ID variables to add to the form data. This is similar to 2 but involves marginally less rewriting of what I already have there, though still would require me to reshuffle things.

On the bright side, I started out playing with my code tonight not knowing what the problem was and now I’ve not only identified it, but I know why it’s happening (vaguely — basically, if you ever pull data from a database and you don’t order it, you’re kind of asking for randomness) and I also have three viable (if unlikable) solutions.

So there’s that.

Once I’ve done that, I then need to calculate/check the answers. So the plan is that if you get 0 through 5 answers correct, you fail and you get to try again the next day, with new category choices and new questions, as previously noted.

If you get six right, you pass. But then I also want to add rewards for getting 7, 8, 9 or 10 questions right.

My game design “skills”, such as they are, basically do not care about the level of my PHP skills. Like, not in the slightest. As such, my PHP skills are having trouble keeping up with my imagination. Every time I want to add something “cool”, part of me (the part that has to figure out the logic to it for coding purposes) yells at my imagination to say SURE YEAH WE NEED A TON MORE COMPLEXITY IN THIS GAME RIGHT NOW, WELL-DONE, JULIE! It’s not fun to war against your creative side and your logical side, but I guess this is my life, now.

What else is my life? Well, there’s kind of a global pandemic sweeping across the earth. I have not left my apartment building in nearly three weeks, but I also work from home, so it’s mostly business as usual here, interestingly. My greatest worries are running out of milk and not being able to run to the corner store and also not being able to book a grocery delivery before my milk runs out.

Work is busy — like Black Friday/Cyber Monday levels of busy — so I haven’t had a ton of time to code, despite the pandemic. All kinds of people are like “PICK UP A NEW SKILL” and I’m like “can I just have a nap, please?”. I’m excessively thankful that I’m not needing to worry about my next paycheque or being able to afford milk and other groceries, so I definitely can’t complain about being busy. I mean, I can, but it makes me sound like an ungrateful wretch when I am, in fact, eternally grateful to not have to worry about things on that front.

All of this to say, I have no idea when the beta of my game will be out, but I hope hope hope 0.4.0a (which will have Challenge 1: The Rapids in it) will be out by the second week of May. Target is roundabout May 10. Maybe. Hopefully. We’ll see. And that same weekend, I’ll revise my own targets for deadlines and stuff.

And now, bed, and more coding tomorrow. I hope you and yours are well during this troubling time, and please don’t feel like you have to learn a language or pick up an instrument. Some days, all we can do is exist and, frankly, that’s okay.

Game Progress

Mobile responsiveness went out, as scheduled, with patch 0.3.0a on January 26. It’s not fancy-shmancy, but most things should look decent on any size of screen. Hooray!

I released version 0.3.1.a on February 29 because, really, who can resist deploying on Leap Day? Not me, that’s who. It was just a tiny thing to add a small chance, under certain circumstances, to encounter a special event while foraging for food.

I was pretty excited to get this to work because it had basically given me a headache. But I persisted and got it done.

So now, I’m working on the first of the three challenges: The Rapids.

The thought here is that someone gets 5 random categories presented to them and they pick one. Then, they get 10 random questions from their selected category to answer. The catch? They have to answer as many as they can correctly within 60 seconds.

Obviously, since I wrote most of the questions, I can get through them quickly. I can get through ten in like, 30 seconds. Here’s a video of me showing the challenge as I work on it.

I’m definitely not exactly the target audience, but I figure I’ll start here with 10 questions and 60 seconds and I can either drop the number of questions or increase the time to 90 seconds. You don’t have to get all ten right (the pass mark will be six, I think) but the more you get right, the more bonuses you’ll get. At least, that’s the thought.

I’m literally at the point where I’ve got the ten questions submitting automatically at 60 seconds but, in my testing, I came across a bug.

Refreshing the category selection screen produces more choices. And the same thing happens with the questions that are generated.

So I’ve been working on storing this information in a new database table for challenge data. There will be three of them, so may as well give them their own table.

The table started out with 18 columns and then just grew as I copied it for more challenges. So this way, it’ll give you back the same categories and questions, if you reload, as they’ll be stored in the database.

Again, I wonder why I do this to myself. Why do I add complexity? LET PEOPLE CHEAT, JULIE!

But no, I don’t want people to “cheat” and refresh the categories regularly until they get one they can do, or refresh questions until they can solidly answer half or more. Stupid idea of “fair play” or something, I guess!

So what happens if you don’t pass the challenge? Well, good news — I’m going to wipe the values from the database during maintenance, so you have another chance the next day to get categories and questions that are maybe more favourable to you.

Frankly, I think it’s generous! A choice of five categories, not three, and a reset daily if you fail, with no other repercussions other than you cannot actually continue on your journey. Hell, you could set up camp and fish and forage for the rest of your time in the game, that’d be fine, if you wanted.

It’s times like this that I feel like an evil game designer, cackling to herself. Like the Super Mario Bros. designer who was like “oh yeah, let’s have 8-3 be a goddamn nightmare with the Hammer Brothers everywhere!” or the person who designed the Turbo Tunnel in Battletoads.

Still, I’m coming at this from the point of view of someone who loves games and has played them her entire life, starting with Pac-Man on the Atari 2600. River Raid was my favourite Atari game. I grew up on BBS games like Trade Wars 2002, Legend of the Red Dragon and Sky Mountain. I played Sierra games every chance I got, loving the quirky sense of humour found in the Space Quest games, the silly puns and odd happenings in the King’s Quest games and actually being scared by the happenings of the Police Quest games, so invested was I in the life of Sonny Bonds. I loved Déjà Vu and Déjà Vu II: Lost in Las Vegas, which taught me about how to hide evidence so I wouldn’t go down for a murder I didn’t commit, and how to cheat at poker with an old boxing buddy.

So, really, this is a game I’d like to play. It’s still in its nascent stages now, but I’m still working on it. Finishing up The Rapids is my goal this weekend. Fingers crossed!

Mobile responsiveness work

So the thing about making things mobile responsive is that it’s a user interface and user experience issue. It’s not a game issue. It’s not something I can fix by tweaking the PHP function, it’s not something I can fix by rewriting some logic.

What is it? It’s finicky, that’s what it is.

Obviously, I should have done a mobile-first design. I always tell myself I’ll just throw the website together right quick and then if I feel like it, I’ll go back and make the site mobile responsive. And basically I never do that. Although I did follow that idea when I put together the latest version of juliemartin.org, but that was yonks ago and it’s also not a slick-looking site. Look, website design has never been my forte. I can do it, I can do all the things, but it’s a bit tedious and it’s a bit boring for me.

It’s funny how I’ve changed over the years. Literally 20 years ago, there was nothing I loved more than playing with website design and using CSS and little snippets of JavaScript to change the look of my websites. And now it’s like… that’s not challenging enough. It’s just finicky enough to annoy me to mean I don’t really have mastery over it and that it’s not easy, but it’s not like it’s difficult to get things to look the way I want them to. (Note: it is still challenging to get things to look pretty, but that’s a whole other failing of mine.)

I’ve set next Saturday as the tentative date when I’ll launch patch 0.3.0a, which would include mobile responsiveness. I started tinkering with it around 3:30am this morning, like 12 hours ago, gave it an hour and was relatively satisfied with what I’d accomplished. But I’m not looking forward to the rest of the work. The <div>s related to the questions being correct or incorrect, or getting a fish or not, or finding food or not, all of those are annoyingly tricky as it is, so I do not relish the thought of trying to make them responsive. I guess we’ll see how finicky it is, eh?

Following up on my previous entry, I also started trying to code a 1% chance of a fun and random thing that happens, but I’m stuck, which is infuriating. Errors crop up everywhere! But why? I may have to shelve that ’till 0.3.1a, along with another 100 questions or so.

Finally, I wrote up an article at DEV about my experiences while writing the game and how you should just do the thing. I didn’t have everything planned out when I started and I still don’t know a ton of things and yet… here I am. Doing the thing. Writing the game. Learning things.

And on that note, I should probably go back to my CSS…

Patch 0.2.0a is out!

My dudes, I did it. I merged and deployed Patch 0.2.0a of River of Kurn exactly when I intended to! I am very psyched.

Patch notes are here at the forum: https://forum.riverofkurn.com/discussion/13/river-of-kurn-patch-notes-patch-0-2-0a#latest

Essentially, I rocked it. I:

  • built my question importer tool which works beautifully
  • fixed expiring sessions by modifying my php.ini to add session.gc_maxlifetime = 3600 and then adding some stuff to my pages that set the original lifetime of the session to 3600 seconds (1 hour) and then some math on each other page to determine if it’s been more than an hour since the session was last active. If so, it redirects you to a logged out page where it explains what happened. Very proud of this one!
  • refactored my change password function so that I could then implement a forgot password function. Which, you know, I had forgotten to implement in the first place! Whoopsiedoodle.

I did a couple of other things, which also included adding 100 Star Wars questions (no spoilers for The Rise of Skywalker, I promise!) and 100 questions on Human Biology.

I also posted to the RiverOfKurn Twitter account:

@RiverOfKurn

And I sent out the first issue of ROK News, the River of Kurn newsletter! You can see it on the web here.

Whew. I need a nap. (It, uh, may be 5:22am and I may not have slept yet…)

Anyway, another thing I’m doing, because I have no experience whatsoever in game design, is taking Will Wright’s Game Design and Theory course at Masterclass. Check out the preview here:

https://www.masterclass.com/classes/will-wright-teaches-game-design-and-theory

Will Wright, in case you’re unaware, is responsible for the Sim-type games. SimCity, SimAnt, SimCity 2000, The Sims, Spore. The list goes on. I have, legitimately, spent hours, perhaps weeks or months of my life playing this man’s games. Certainly, he knows stuff that I don’t.

I decided to go with the “all-access” pricing, because $120 CAD for a single class versus $240 CAD for a year of access to every single class was just a no-brainer. They have Shonda Rhimes, Aaron Sorkin, Garry Kasparov, Malcolm Gladwell, David Sedaris, Neil Gaiman, Margaret Atwood and so many more that I’d love to learn from, particularly when it comes to writing. But it was Will Wright teaching a class that got me to pony up the cash.

This isn’t sponsored in any way, I promise. I am just blown away with how detailed and what high quality the class is. It’s amazing. There are workbooks! Exercises! Homework! (I admit, I have not delved deeply into the homework side of it yet.) But just the lectures alone are amazing. My brain is teeming with ideas on how to refine my game just from the perspective of play. Like, what would make things more engaging for the players? What would allow them to feel more in control of their time on the river? Super exciting to be feeling so creative right now, let me tell you.

One of the things I’m thinking of adding is a daily game with your guide on the river, Dorene. If you can answer her question correctly (or win her game or something like that), you have a chance to win a reward of your choice, with one of the rewards being a surprise.

That surprise can be good or, because Dorene is a water nymph and is mischievious, it could be bad. I’ve already come up with the different options with 10% chance for two of the best things and 25% chance for the third-best thing, with a combined 55% chance for the two bad things. I actually cackled while writing it all down.

Then, thinking about random happenstances made me remember some of the Legend of the Red Dragon random events. I would love it when I came across a horse, for example, or got refreshed (max HP) or any number of little things like that, so I’m going to add in at least one of those, too — probably a 1% chance to occur when you’re foraging for food and have under a certain amount of energy.

Of course, the big question is “when”. hahaha, yeah, I have a lot of work to do already, so we’ll see where I can put in some of this more compelling gameplay stuff. Some bits would be easy to implement, some would be harder. I also deliberately wanted to be vague about how the game works, to let people figure it out for themselves, the way I had to when I was a kid playing Trade Wars 2002 and Legend of the Red Dragon and Sky Mountain. I can always add information or warnings or clarifications or notices to the game, but I can’t remove the information once they’ve taken it in, which would ruin some of the fun of discovering things.

As Will Wright puts it, it’s about finding the state of flow. If it’s too hard or unnecessarily punishing or complicated, then people will never gain interest in it. If it’s too easy or too simple or too boring, people will tire of it easily because they’ll master it quickly. (Think of tic-tac-toe — adults have no interest in playing because we’ve mastered it, but a 5yo would love it. Note to self: play tic-tac-toe with eldest nephew next you see him.)

The ideal state is the state of flow, where it’s hard enough but doesn’t punish you unnecessarily. Humour helps and so does the feedback you receive when you fail. After all, so much of playing a game is failure and learning how to do things better.

When I played World of Warcraft quite seriously, my favourite thing to do was to raid. I loved being in a group of 40 or 25 people and taking down a difficult encounter. (But honestly, I never again want to hear Sindragosa threaten me as my pathetic magic betrays me.) But I didn’t mind wiping over and over again, as long as we gained more information on the encounter. Like “oh my god why did we all just blow up???”, figure it out, fix the problem, then don’t get blown up and progress in the fight. Except then something else would occur, inevitably, hahaha.

One of my toughest learning encounters in World of Warcraft was the 25-man Heroic Blackthorn, in the Dragon Soul raid. The entire encounter takes place on an airship and the first phase is brutal. The second phase is worse. But the worst part for us was everyone dying in the first 30 seconds of the encounter. Something would be missed and we’d take damage. Or someone wouldn’t hug their buddy and the buddy would die. Or someone fell off the airship. It was maddening because we couldn’t progress far enough to figure out what the hell all the different problems were. (There were three separate issues that we had to iron out, as it happens.) We eventually got through it and the footage of us all dying constantly was pretty hilarious, in retrospect. At the time, though, that felt punishing. It felt hard for no reason. It made all of us want to give up in a way I hadn’t felt for a long time. (Did I mention the airship was on fire for the majority of the fight and the fire was buggy as all get out? Lord.)

Anyway that’s kind of where I think my game is at right now. The questions are a little hard and players don’t have quite enough agency. So on one hand, my game is a little too punishing (for no reason) and on the other, it’s kind of simple and boring.

It’s a very interesting problem to have and it’s a fascinating balance to want to strike.

All right, it’s late. I need to sleep. Back to work on Monday after 16 days off in a row. Hopefully I’ll still be able to work regularly on the game and get mobile responsiveness done for January 25…

Progression and Regression

Well, I’m kind of surprised it hasn’t been longer than nearly four months since I sat down to write here! Go me. That feels like progress of some sort. Maybe.

And speaking of progress, there has been very little progress on River of Kurn of late. This is for a number of reasons. First, November is National Novel Writing Month, in which I participate annually. Once again, I managed to finish 50,000 words of a novel in the 30 days of November! And that meant zero coding, because I also helped plan my own high-school reunion (never you mind just how many years we celebrated), plus work was wild. December arrived and work was even wilder, plus those pesky “holiday” things ate up time in terms of thinking, planning, shopping and preparing.

I did make some attempts to code in October, but failed miserably because I got stuck on a totally optional thing. You see, I wanted to build myself a tool to add more questions to the game easily. Of course, adding them isn’t that hard in the first place, but it was infuriating to add the questions to the questions table, then add in rows for those questions in the statistics tables for the blue game as well as the green game. And if there was an issue importing, I’d have to dump the numbers out of the question table and reassign numbers to the questions before attempting again, or I’d go from, say, question 1331 to 1381.

So I was stuck. I’d never coded something to import from a file before. I can do database dumps and backups, but I had never tried to bring data into the database programmatically before. So I got stuck and then I got busy.

I’ve been off work for a full six days now (and have another 10 to go!) and the holidays are now over for me, so when I woke up at 4am today for no apparent reason, I decided to reorganize my plans for my game and I decided to tackle this import issue.

Four hours of testing, testing, testing and testing some more later, I now have an import tool built into the admin section on my game’s website. I mean, it’s not live yet, I’ll do that when I finish adding another 100 questions (about Star Wars this time) and add a couple of other things to the game. I’m going to rework an introduction question, add text to explain the validation link will be sent to the email address you provide, etc. Anyway. I am super jazzed about this, because it makes adding questions so much easier. I literally browse for the CSV file on my computer, upload it and it does everything for me. Victory! (Another victory: managed to renew the SSL cert for the game site and am feeling very proud about this because it was NOT simple.)

In not so great news, my EVGA GTX 1080 Ti video card died on me just over two weeks ago. It lived about 16 months. I saw my holiday plans of gaming and coding vanish before my eyes. While I could always use the integrated graphics to at least use a monitor and actually use my computer, that’s no way to game. I also have a pretty crappy video card that’s been sitting in my old computer, so that’s what’s in my new computer now. I can’t do much in the way of gaming, but I can power a second monitor, so I can at least get some coding done! (As evidenced by my building my import tool.) The other piece of good news is that I was under my manufacturer’s warranty, so I got approved for an RMA (return merchandise authorization) to send EVGA my card and they’ll send me another one. The bad news there is that even though I paid for 1-day shipping, they only attempted delivery on Tuesday, December 24 (and not Monday, December 23), which means that EVGA was closed. Obviously, they were closed on the 25th as well.

Thankfully, the delivery was accepted on the 26th. But now we’re probably looking at them shipping a replacement next week. And, well, their site says “shipping for online/RMA orders will stop completely on Tuesday, 12/31/2019 at 2pm Pacific Time” and will resume the following Tuesday. So if they don’t ship it out today (Friday) or Monday, I probably won’t get my video card until, uh, mid-late January. Even if they ship it today or Monday, I probably won’t get it before the end of my vacation time. This is the universe’s way to tell me to catch up on TV and coding, I guess.

So that brings me to my plans for 2020 for River of Kurn:

  • 0.2.0 release scheduled for January 4, consisting of: 200+ more questions, the tool I created, other bits and bobs and hopefully a way to keep sessions active or allow them to fail gracefully.
  • 0.3.0 release scheduled for January 25, consisting of making things work properly on mobile.
  • Beta release scheduled for February 29, consisting of 37 separate issues… hahaha oh boy.
  • Full release scheduled for July 1, consisting of an additional 15 issues.

And, of course, since adding questions are so much easier now, I’m hoping to add more questions much more regularly.

So that’s what’s up with me. Hoping to post more frequently here, too!