Thursday, January 1, 2009

Year 1

Today is the first day of the new year.

If you're browsing any of the open-source game websites out there, you've no doubt noticed that my game is not on them. Nor is it just pending; sadly, I missed my goal for last year, which was to actually finish this game.

For a recap of what happened, see my postmortem - nothing's changed since then, except for the "this is doable" part. Obviously I missed that one :)

Still, the stats on the right show the story: As of right now 327 hours and over 27,000 lines of code. What I didn't really grasp when I started this last year was the fact that this game is huge! November really brought that into light, considering that given the effort I put in during just one month I could have finished an entire novel.

Where next? I'm not sure. The game is still fairly near to completion, so I'm confident I'll actually get it out this year given a similar amount of work. The question is: Do I want to put in that much work? As far as I see it, here's my options:

  • Keep working on the game, an hour a day, until it's done. This is the option most likely to actually get something done, at the risk of burning myself out.

  • Work on a different game: "All Kuiper, All the Time" gets very tiresome after a while. Especially over the last month, just contemplating working on the game was an unpleasant experience. Doing something completely different might help.

  • Do something completely different: Go back to writing novels and gaming, programming on the side. Essentially this is the eclectic blend of stuff I was doing before I sat down and made a schedule for myself. The upside being that it's far more relaxing, the downside being that nothing ever actually gets done.


Obviously, I'm leaning toward the second option, or maybe even the first with a somewhat relaxed schedule.

Tuesday, December 9, 2008

Day 332: Hindsight

In retrospect, it would have been a good idea to make the "have you completed this mission" system a little more unit-test friendly. More on that in a moment.

Every fleet the game is going to have for part I is done. You may have noticed how I keep talking about parts of the game and whatnot. Why is this? Well, the plot's in three parts. How will the player know? That's the other major ticket I completed today: Banner states. Simply put, this scrolls things (probably words) upward so the player can read them, so I can now create all the "PART II: The Revenge" scrolling goodness I want. I've already implemented the game's credits screen this way.

I also started making the random missions for my game. In any coding project, I'm always a bit wary of returning to some functionality I haven't used in a while, for fear it'd broken somehow in the meanwhile. As superstitious as this sounds, it happened to be the truth this time around: My junk was broke. Some of this was changes I'd made in the meantime, and some of it was the fact that parts never worked correctly in the first place.

For instance, random missions. My testing of this involved generating one and then flying around and making sure it worked. That was fine. What I neglected to do Way Back When I first made the functionality was test it any further. It turns out, when a random mission generator makes more than one mission, it tacked on the conditions for every other mission it generates. Oops.

Tuesday, December 2, 2008

Day 325: Label Randomly

Yesterday I took a well-deserved rest.

Today I figured I'd take an easy ticket, the one whereby I make random missions accept labels. As though welcoming me back to coding my game, this was far more difficult than I'd wanted it to be.

The first step was to adapt the KuiAtCondition to also respond to labels. As it is, you give it a list of destinations (either planets, organizations, or sectors) and if the player is there, it passes. It seemed simple to extend this for labels....

It's never easy.

For one, only the root KuiObject knows how to handle labels, and I'd hardcoded that in. My choices were: Refactor labeling out to a more generic module, or copy and paste the code. For once, I did the responsible thing and refactored. It took an hour!

The refactoring turned out to be worthwhile, as it happened. I needed to do similar label handling in at least two other places later, so as usual, it paid for itself.

Still, it's never easy!

Sunday, November 30, 2008

Day 323: Game Over

Today marks the last day of National Game Finishing Month. I closed five tickets today, mostly content-related. Every ship that's in part1 of the game is now created. Every weapon that's in the game entirely is done. Even helpful standard addons have been made.

In conclusion, of the list I made yesterday, half of the items are now done. So now, the NaGaFiMo postmortem!

  • What went right

    1. Effort The spirit of this exercise was to devote my Nanowrimo time to the game. I've done more than that - as of today, I'm nearly 4.5 hours ahead of schedule. If it were a novel, it'd be done by now.

    2. Learning While I won't say that I haven't learned anything from the rest of the programming I've done, I've definitely learned more this month. Specifically, I had to create new art via Blender, which I knew how to do long ago but have since forgotten. Making art is definitely out of my comfort zone, but I learned quite a bit.

    3. Atomic Coding The linked article talks about the practice with Subversion, but I've found it even more effective using git. Having a local repository lets you commit nearly everything once you've made the smallest workable change, yet not embarrass yourself by pushing out to the remote (public!) repository.



  • What Went Wrong

    1. It's Not Done! The goal of this was to actually have the game finished by now. That didn't happen, but given that I actually put in all the work, I count this as a failure of estimation rather than of effort.

    2. Learning Yes, that was above on the 'what went right' portion. The downside to learning how to use a tool like Blender is that I had to take time away from the rest of the project in order to do it. If I'd already known blender or already done all this, I'd have ended up a lot closer to the original goal.

    3. Going Dark Though I updated the blog when I was done with major features, I didn't update daily. As I've found the blog to be useful in the past, I'd like to keep it up.



  • What I learned

    1. This is Doable This particular schedule works for me. I initially thought 1.5 hours a day might be somewhat difficult, but though not easy, it is at least workable.

    2. Get it Done Rather than putting off seemingly unrelated work until it absolutely must be done, it's probably better to learn these things when it won't interfere with big goals

    3. People Might Actually Play This I've had a number of requests for the demo, which while being exceedingly out of date is still a reasonable facsimile of how the game plays. My novels have had only a few token readers, with the vast majority of people who inquire not bothering to actually read them. Everyone who asked for the demo has played it however, making me think that I may have better luck!



Saturday, November 29, 2008

Day 322: The End is Nigh

National Game Finishing Month is nearly over. Tomorrow I plan to do a marathon of getting stuff into the system then blog resignedly about it. Today, however, was all work.

Specifically, I animated the rest of the ships. Then I created the standard ones in-game, and used Mass Distribution to push them out to every standard planet in the galaxy.

High profile things left to do:

  • Random Missions should use labels: The mission system in general could use an overhaul to use the labels, too. It'd be handy for an "are we there yet" check to include "anywhere with this label" as a satisfying condition.

  • Fleets: Once I have the ships done, I need to put the patrols, pirates, traders, visitors, etc, in their place so they'll show up in the sectors they're supposed to.

  • Alliance/Rebel weaponry: The war-fighters should have better weapons than you as a regular pilot should get (but you can get them later, when you join)

  • Alliance Ships: The alliance has three ships specific to them.

  • Rebel Ships: Likewise, the rebellion also has ships just for themselves.

  • Standard Addons: I don't think I'll have faction-specific addons unless I really get inspired.

  • Random Missions: These are essentially the filler of the game.

  • Scientist Scout Missions: This is the essense of the plot for the entire game, right here.

  • Alliance/Rebel Scout Missions: The only thing close to a major sidequest, this is the initial alliance/rebel war.

Wednesday, November 26, 2008

Day 319: Blockified

Every single time I do graphics for anything, I have to re-teach myself Blender, which I'm actually somewhat decent at. It turns out my wife has an eye for what would make spaceships look even better, so I've created quite a few. I should now have every ship I need.

I rendered all 36 frames of one of the ships before remembering that I had no way to change the 36 individual .png files into the one giant .png file that the engine could handle. I've written this script easily twice before (once for TraderMissions, and once more for a pyweek competition). But I couldn't locate the first script, and the second one wasn't suited to my current engine. So I had to, once again, write the script.

It was an easy task, for once. blockify.rb is a pretty brittle utility without a lot of other uses, but it gets the job done and hopefully I won't have to re-write it next time I need it!

Sunday, November 23, 2008

Day 316: Weapons of Ordinary Destruction

I fixed an important bug today: In the old system, changing an object's tag after it had been created was a bad idea. The game would simply crash upon reloading, if not sooner. The new system exchanged this fatal bug for a more subtle one: Re-naming caused duplicates to exist in the repository (the old name stuck around).

This sounds trivial to fix - just see if there's an old tag and delete it. However, objects which are duplicated (like, say, weapons) always have the old tag of the object they were created from. So any new weapons were destroying the old instances.

But can't I check to see if they're being duped? Yes, I can - now. Most of my coding work today was enabling exactly that. So now you can change an object's tag, and unless you change it from object_thing to object_thing:4490, you're fine.

Hint: Don't do that.

Finally, I created every weapon I wanted to be available to the player at the start of the game, and distributed them to all the planets where I wanted them to be available.

Unfortunately, I used up all of the weapon art I had in TraderMissions, thus meaning I'm going to have to create new stuff soon. Re-learning Blender, ahoy!

Saturday, November 22, 2008

Day 315: How not to use Mass Distribution

The next big thing on my plate was to create the various cargos that the player could buy and sell. This was aided by the fact that I'd already diagrammed out how much I wanted the low,high,and medium versions of those cargos to cost.

I started with 'Food'. It's cheap on Earth because of the lots of landmass. So I created a cheap version of food, and moved on.

It then occurred to me that this was going to take /forever/. I'd have to create 3 states for each of the different cargos I wanted to sell (and as of now there are 6). Also there'd be no consistency between prices. A low 'food' price could be half the price of medium food, while low specimens might end up half a buck off.

"Wouldn't it be nice", I thought, "To be able to automate this in the editor somehow?"

Yes, yes it would. And since I'm the guy who wrote the editor, I did it. There are now 'auto low', 'auto medium', and 'auto high' buttons in the cargo editor, which set the values and names of the cargo to 15% lower, the same, or 15% higher than the base price, respectively.

This would still require me to create all 18 cargos. Wouldn't it be nice, I thought, if when you create a cargo blueprint it automatically created the low/med/hi versions of itself?

Yes, yes it would. And so again, I did it.

Here's where my brilliant plan fell down. The planets hadn't been tagged for specific cargo. So while a number of planets shared the feature that their food was cheap, I hadn't tagged them to take advantage of that and use the MD system to do all of this at once. I had two alternatives:

  1. Go through all the planets and re-tag them

  2. Go through all the planets and just add all the cargo I wanted


As these were equivalently labor intensive, I did the second. That's when I ran into another problem: When the cargos are automatically created as outlined above, they're just tossed into the repository. The repository stores everything in a gigantic dictionary, which of course means they're unsorted. So I still end up looking at a list of 18 different cargo items, all in arbitrary order.

Wouldn't it be nice, I thought, if those were sorted?

Yes, yes it would be. Done!

I again reiterate that, as frustrated as I've been in the past by editors for other games, it's enormously liberating to actually be able to do something about it :)

Sunday, November 16, 2008

Day 309: Mass Distribution

The Mass Distribution (or, as I shall refer to it from now on because I'm already tired of typing the whole thing, 'MD') system took me a few days, and then it was done.

To recap: The idea behind MD was that I could label objects (say, sectors) in a certain way, and then distribute objects (say, fleets) to aforementioned sectors. So if I'd created a trading fleet, I could put it in every inhabited sector at once rather than one-by-one going through each sector and adding the fleet manually.

The only thing this really required was some GUI work (the actual adding of the objects was, as it turns out, ridiculously easy), but it required something I hadn't created before: Namely, a way to find any object in the entire universe. Thus was born:


THE OMNICHOOSER


On the top-left, all the model classes in the game. When selected, the results show every object of that type. The top-right features every label in the game, and when it's chosen it'll show every object with any of the selected labels. When both are active, it shows all objects with any of the selected labels of the given type. For my example above, I picked "KuiFleet" and "traders" to get the trading fleet I'd just mentioned. There's another one of these for the 'destination' objects (i.e. all the sectors in the universe) - there I chose "KuiSector" and "inhabited". A few button clicks later and I'd placed 20-some-odd fleets.

What this means is that I'm likely to return to creating actual content soon. I haven't kept the blog updated because I've been doing the same thing every day ("Look, listboxes are broken! Look, the OmniChooser is broken! Look, both are broken at once!") but hopefully now the MD will speed everything up and I'll have more to say.

Sunday, November 9, 2008

Day 302: RTFS

I finished Phase II of the great XML change yesterday. I would have posted then, but there was testing to be done to make sure it was Actually Fixed This Time, Dammit. I'm discouraged by the number of bugs that this change uncovered in my code - that is, not bugs in the new code I wrote, but code I wrote months ago and has been working fine since. This includes bugs of the "How did this ever work in the first place?" variety.

But that's all fixed, at least until I discover the bugs in this code a few months from now.

I've been trying to use XSLT as my patch tool of choice, and so far so good. Only I found a bug where it wouldn't preserve linefeeds in attributes, which was important because a lot of my descriptions ended up being like this:

<sector name="foo" description="Name.

Here is some other stuff about this
sector. That linefeed's important
because I don't want to go back and
manually put linefeeds where they
should have been."/>

No problem, I think, because I'm still somewhat new to the XSLT scene there's probably something I missed. Hours of all the whitespace-preserving options I can find, and no luck. Finally, I find the answer.

The coding gurus of Stackoverflow were the lucky ones to inform me: It's not a bug. Not preserving whitespace in the attributes is actually part of the XML Spec.

The only way I got away with it for as long as I did was because Ruby's XML parser was ignoring this fact. So I wrote a ruby script to do the transformation. I felt somewhat relieved that it wasn't actually my fault things weren't working out, there was a bug in REXML. Then I realized that, if I hadn't broken the spec to begin with, I wouldn't be in this mess.

Thus the Programming Tip of the Day: Even when it's not your fault, it's probably your fault.

Saturday, November 1, 2008

Day 294: NaGaFiMo

It's National Game Finishing Month!

My next big part of the game to do is mess with the XML some more - specifically, making it look sane as I advocated a few entries ago. But that would require me to muck with XML again and after the nightmare it was last time, I declined to do so.

Instead, I closed out some old improvements I'd been meaning to do for a while:

  • Ownership: The player will now see what faction his/her target belongs to.

  • Fuel Regeneration: By default, fuel will now (extremely) slowly regenerate now. So if you're stuck out in the middle of nowhere with no fuel, you can just wait. It'd probably still be faster to save your game and change your ship's 'fuel' value in the XML, but now people less inclined toward cheating can continue to play.

  • Description Comments: Sometimes I want to remember something about a planet or sector, i.e. "This is the place where Act I ends". There's no place for comments, so instead of taking the easy route and making a do-nothing 'comments' field, I made it so any string surrounded by /* ... */ would not appear if the game wasn't in edit mode. Instant comments!



I've got to get to that XML at some point, though....

Friday, October 31, 2008

Day 293: No Nano

Lately I haven't been hewing to my 'one hour per day' quota. At all. Whatsoever. And suddenly, hey, it's November and I'm looking at two months until my deadline for releasing this wacky thing. November is, as I've alluded to before, National Novel Writing Month, and I've wanted to participate this year.

THAT ISN'T HAPPENING!

Instead, I'm dedicating my NaNo time to working on this game - an hour and a half per day, every day. My goal is to actually finish everything by the end of the month, giving me a month to hand over the beta to people and watch as they rain bug reports upon my poor undefended soul.

I started a day early - I began phase 1 of my XML overhauls quite a while back. I was suffering from "arrow XML", which looked a lot like this:

<object>
<child name="foo">
<other_object>
<child name="bar">
<yet_another_object/>
</child>
</other_object>
</child>
</object>

Now imagine it nested about twenty levels deep.

It seemed like it'd be fairly straightforward to write each object out one by one and then just refer to them by ID, but - as it turned out - it wasn't. Changing the way my parser worked exposed some deep bugs in the system that I hadn't seen before, and I was forced to quash them!

Now, however, it works. Thus, National Game Finishing Month begins!

Tuesday, October 14, 2008

Day 276: Rebel Yell

Much like the last blog, much work was done this time around on the planets. As you might deduce from the title, this time around I did all the rebels. What this means is that I'm done with planets....

Which pretty much means I'm done with normal content creation altogether. I'm going to have to go ahead with my earlier mass-distribution system, which means lots of coding. I'm not entirely sure how I feel about that. On the one hand, it was always less tedious to code than make new content for the game. On the other hand, making new content was a very casual thing, I could just sit down and work for a bit. We'll see how it turns out.

Other things include me re-thinking the XML I'm doing. Here's what it looks like now:

<sector x=5 y=7 ...>
<child name="planets">
<planet .../>
</child>
</sector>

There's a lot of stuff being replaced by those ellipses. And I mean a /lot/. Multi-line text fields are the most common. I'd like to merge them as their own elements. So it'd be something like this:

<sector tag="foo">
<fields>
<x>5</x>
<y>7</y>
</fields>
<children>
<planets>
<planet/>
</planets>
</children>
</sector>

It's more verbose, but I also think it's an easier read. At least, when I'm debugging, it's a pain in the ass to try to locate the one field I need in a sea of text. This way they're at least on their own line.

Converting between the two will be... interesting. I think I'll start a data-format versioning system so new versions of the game will be able to understand old/differently formatted data, or at least reject it out of hand. Then I'll use the magic of XSLT to change everything I've written so far from the old format to the new.

I just learned XSLT recently, and I'm liking it. It may end up being my patch tool of choice!

Tuesday, October 7, 2008

Day 269: Alliance

Oh, my lacking blogging/development schedule.

Today I finished up every single sector of the Alliance by tagging and placing planets where they belong. And very little - if any - code was written in the process.

As evidenced by this rather short entry, I have a great deal less to say when I'm making content for the game then when I'm coding.

Ah well. Entry post go!

Monday, September 15, 2008

Day 247: Express Yourself

As mentioned yesterday, in the Bad Old Days (i.e. those before today) you had to name something and then give it a descriptive tag which was often just the thing name re-branded. Well those days are over!

The 'auto' button now takes the name and creates a tag for it. So:

Name: The Best Player in the World is from a City in an Arboretum

Becomes:

Tag: player_best_player_world_city_arboretum

So the tag is based on the type of object, plus a scaled down version of the name. As you no doubt noticed, I took out a bunch of connector words there (mainly articles). This involved regular expressions.

At first, I was doing something like this:

name.gsub!(/\sthe\s/,' ')
name.gsub!(/\sa\s/,' ')
name.gsub!(/\san\s/,' ')

Yes, I had one line for each thing I wanted to remove, which is of course silly. So I made a list of all the excluded words and tried again, only I ran into a problem. It's not a string I'm using for matching here, it's a regular expression - meaning I couldn't just throw the current loop value in the middle and expect it to work!

Luckily, there's a way to do exactly that:

exclusions.each do |x|
excludeMiddle = Regexp.new("\s#{x}\s")
name.gsub!(excludeMiddle,' ')
end


Regexp.new takes a string, from which it'll create a regular expression. And I can do all the manipulating I want within strings!

Also I made a few more planets using the new autotagging feature. But that's not as exciting.

Sunday, September 14, 2008

Day 246: Checking In

This time, I've been half working, half slacking. Though I did take a few days off, I also continue to face the fact that "Made some planets and tagged them" remains a very boring blog entry. So I'm trying to split my time up even further - 30 to 45 minutes for the planets, then 15 to whatever else I feel like doing for one of my many features I haven't yet implemented.

Today's feature was putting an 'auto' button next to the 'tag' input. So now, instead of naming something "Monster Island" and then having to click down to 'tag' and type "planet_monster_island", you can now just hit the 'auto' button and it'll come up with that for you. Well, it would if it worked - right now it just says "You clicked the auto button!"

Features I did previous to today include accidentally creating a planet I didn't mean to and then realizing that I had no way to delete planets. You'd think I'd have learned my lesson after making the exact same mistake with Sectors.

Sunday, September 7, 2008

Day 239: Mass Effect

I started this blog because I saw a number of my fellow developers making dev-blogs for their projects. I had two thoughts:

  1. I won't have anything to blog about: This was the primary reason I haven't blogged in the past, I'm just not that interesting. In this case, though, I can blog often because this is a daily project. Lately, as you've no doubt noticed, this practice has fallen by the wayside. I've continued to work, but writing up the blog post takes a lot more time and so I've tended to skip it.

  2. Nobody will read it: How I'm developing my game is of little interest to anyone except pretty hardcore game developers who are familiar with ruby, rubygame, and interested in my game enough to read about it instead of working on their own. This set is maybe three people, five tops. I've since discovered that having the blog is invaluable - I've searched through it a number of times to find how I did something earlier, and the fact that I blogged about it made it simple to look up. Even if no other living soul even glances at this blog, it's already been of enormous use.


So that said, the slow pace of blogging may continue. When I'm writing code, I often have something to say about how I implemented it. When I'm developing content, what I have to say is pretty much "Created a few sectors".

Now, however, I'm coding. I created a ton of sectors and a few planets, and it occurred to me that later, when I've made a "standard array" of ships I want the player to be able to buy, I'm going to have to go back to every single planet I made and put those ships up for sale there.

The upside to being the author of a game editor is that if you don't like how it's doing something, you can change it. Today I began work on the "Mass Distribution" system. Each object has labels (like tags, only I call them 'labels' because I'm already using 'tag') that group it, and the Mass Distribution system will allow you to take a ship, a weapon, a mission, etc, and give it to everything that shares a label. So if I, while creating these new planets, label them something like "alliance, standard, human", I can go back and easily give the standard array of weapons,ships, etc, to all the planets which share whatever tags I want.

I may modify the random mission generator to use this technology as well.

Sunday, August 31, 2008

Day 232: Re-re-port

It's been a while since I blogged but unlike last time that happened, I've actually been busy in the meantime. Here's what I've been up to:

  • Ported everything to new-style events. This was fairly easy and straightforward

  • The player can now give their pilot a name. Eventually this will be rolled into savegames, so you can have more than one pilot per module

  • I fixed a Rubygame bug where if your application was minimized and lost focus at the same time, it'd crash.

  • A freaking ton of map work! I have to say that creating maps is a lot easier with an editor. Coming up with ideas for a ton of sectors, however, remains difficult. I made the mistake of giving my initial generic filler sector a description, and so now have to go out of my way to explain how boring the other dozen filler sectors are.


The map descriptions I've written already depict a lot of lore pre-game. There was a time where humanity didn't know hyperspace lanes could go to empty sectors, for instance. After that, the Sandwall spurred the invention of shielding. There was an alien invasion scare at some point. All these are completely divorced from the plot, just things I've come up with as I made the map.

I was asking myself the question: Should I write this down somewhere so I remember it? Then it occurred to me: I just did!

Wednesday, August 27, 2008

Day 228: Demo!

So today I fixed a bug. It was less a bug and something I didn't realize was missing. I mis-clicked while making the map for the new scenario, and ended up creating a sector I didn't need. That's when I realized the map editor didn't have a 'delete' button!

What an accomplishment! I'm totally spent.

Oh, yeah, and I made a demo.

DEMO!!!!!!!!!!

That's right! I loaded Fedora 9 onto my VM and tested the file I just linked to right there. On a pristine Fedora 9 load, it works with no issues. It also runs on Ubuntu! It even runs on both at the same time! On the VMs it chugged down a bit during the combat, which says to me that I've still got more optimization to do, but it may also have been due to the fact that I was running it on a VM while I was also running it on another VM.

That link may not be permanent. It's my home server, so be gentle :)

Tuesday, August 26, 2008

Day 227: Execute!

My current build does not work with the current Rubygame/dev-2.4 branch due to one of my patches having not yet made its way in. It'll die the moment an AI-controlled ship attempts to figure out how to move. This will hopefully change soon.

This should hopefully not matter; the demo itself is looking even more likely to come out this week. Rubyscript2exe is everything I'd ever hoped for and more! Mainly because it will use whatever libraries I have on my system, including my already-patched version of Rubygame. I unintstalled Rubygame from my system entirely, as a matter of fact, and the executable still ran. I'm waiting until I can get it to run on a pristine Fedora VM, and then I'm releasing the demo to you, the public.

Rake can now make .tgz files out of the entire distribution (actually, it could always do that, but I only just figured out how today). This makes my life even easier, because it means I can use rake to build the executable and then put it in a .tgz file for distribution in one step!

Finally, it turns out that Rubygame 2.4, which I'm now targeting as I can't live without my mousewheel support, has the new event classes that will one day be part of 3.0 and which I just finished moving all my code away from. Luckily, I knew I'd have to switch back and made a giant list a few posts ago about what I changed. And I did, in fact, tag the last commit before changing over in git, so a (very) careful merge may turn out to be the easy answer.

Then again, I seem to remember that it's never easy!