The Code Zone Bargain Basement Blog


Imparting Game Development Wisdom of Dubious Quality Since 1998

Thursday, April 27, 2006

The best blog in the whole wide world

I am SO getting these people to make a commercial for my games.

Watch, then stare blankly at your screen for about five minutes.


Oh, and Shetchup is now free. Don't get too excited, though. The version that's capable of importing and exporting to other 3D formats is still expensive, so unless you plan to write a Sketchup format reader in your game, plan to spend the same money as before.

Wednesday, April 26, 2006

Urgh, too danged many languages

I remember back in the heady college days of the 1980's, "mixed language programming" was the touchstone for quality programming. I also remember that it took about a page of code to get a Fortran program to call a function written in IBM 370 Assembly (mainly because the 370 architecture had zillions of registers but no stack). Even during my early professional days at Tandy, calling code in a "resource" (which was DeskMate-ese for a TSR, later known as a DLL) required something called a "funnel binding", which basically meant you stored your parameters somewhere in memory, then passed the location of those parameters in a register so the resource could find 'em.

It was a mess. Writing a system in more than one language was done strictly out of necessity, and even then it was only done with much kicking and screaming.

But looking at this system I'm coding to now, I'm programming in a freakin' half-dozen languages. They all communicate nicely, but I'm dying for some consolidation.

Lessee.

As for the embedded browser-versions, I'm using code written in ActionScript 2, which communicates with some server-side code written in PHP 4, which contains embedded code written in SQL to save out your results to a mySQL database. The pages themselves use extensive javascript to ensure that you're all up-to-date version-wise.

The standalone games are also written in ActonScript 2, they also contain embedded SQL, which talks to SQLite via a DLL written in C.

So that's ActionScript 2, PHP 4, SQL, javascript, and C all working together to get the whole "user experience" to you. Of course, javascript and ActionScript are so similar that there's almost no difference (both being based on ECMAScript). This is offset by the fact that PHP and ECMAScript are somewhat similar but are just different enough to make the whole thing danged confusing.

Weird thing, though, is that I can't think of a more streamlined way of doing things than this byzantine maze of languages all talking to each other. About the only viable "streamline" would've been to go with a Microsoft ASP server, as that would've allowed me to replace PHP with JScript (also based on ECMAScript). But that would've cost more than the cheap LAMP setup I'm using now.

And heck, it's all working so I ain't complaining. I'm just imagining what the 1980's college-me would've said about the 2006 me writing a system in five computer languages, getting it all working, and not having to pass a single goldurned thing in a register.

The 1980's college-me would've probably been amused that no C++ was involved, despite that being the big up-n-coming language of 1989.

As for my favorite, I'd have to go with ActionScript 2. While it does have some evolutionary weirdness brought about by having to remain backward compatible, it's about the best balance between power and ease-of-use and strong and weak-typing. E4X is even better, but it's not available yet unless I wanna switch to Flex.

Monday, April 24, 2006

Okay, back to work

The SQLite glue is now working well enough for me to put into my "production" code, so now it's back to writing games.

I put up a little page for it in the hopes of getting a little interest from the Zinc community. If you wanna see it, it's here. Hopefully a few more folks will put it in their projects, if only so I can get some non-trivial bugtesting.

Wednesday, April 19, 2006

SQLite glues

The SQLite glue-DLL is proceeding apace. Only problem is that this is the first production code in C that I've written in fifteen years, and I'm a mite rusty. I'm using Digital Mars C++ because it seems to carry the least baggage, and it'd just be rude if my little glue-DLL was larger than the SQL engine to which it's gluing. It's standing at 12K with all of the code written, so that shouldn't be a problem.

The IDE is downright archaic, basically the old Symantec C++ IDE with the about-box and icon changed. I like it, though, because the help is nice and simple. All of the C runtime functions and Win32 API's are built as an old-school Windows HLP file. Say what you will about MSDN, but HLP files are great if you don't wanna sift through twelve paragraphs of pontificating just to find out the argument order for strcpy().

Hopefully I'll have something usable today.


Actual conversation with my daughter yesterday morning:

Maggie: Daddy, I need an ipod.

Me: Umm. . .Maggie, what's an ipod?

Maggie: I don't know.

Thus it begins. . .

Thursday, April 13, 2006

okay, here's the deal.

Okay, back to the subject. I futzed around with the Access/Jet functions built into Zinc, and it works beautifully. It's quick and easy. It's be an absolute cakewalk to do all of my persistent data-handling with it.

Licensing isn't really a problem. MS has a rather archaic "Access Deployment Kit" or somesuch thing that gives you a license to distribute Jet. Or you can just own a copy of VB, which apparently also comes with a Jet distribution license. Given that VB is free now, that's an easy one.

Problem is, I can't figure out a reasonable way to deploy the goldurned thing. It's not really a problem if you're running XP or 2000, as both of those apparently install with the Jet DLL's. The problem comes with Windows ME, 98, or even 95, which are still targets you have to look at when you're selling discount software. I'd likely have to bundle separate installers, and that fails the aforementioned "your grandma test".

So I'm back to SQLite. SQLite doesn't bother me at all. It seems like quite a capable little product with the most nonrestrictive license possible (aka public domain).

Problem is, its DLL API, while perfect for stuff like C, doesn't translate into ActionScript well, with things like callbacks and pointers and handles and things that ActionScript jettisoned.


So I'm gonna have to build a Zinc-Sqlite glue DLL. Since the Zinc folks already have three Database objects (MySQL, Access, and ADO) that are 90% identical, I followed their model. The following is about the minimal spec for a "Zinc compliant" SQL object.

// open the database
mdm.Database.SQLite.connect(filename:String):Boolean

// close the database
mdm.Database.SQLite.close():Void

// just returns true if the database was successfully opened
mdm.Database.SQLite.success():Boolean

// run a query on the opened database
mdm.Database.SQLite.runQuery(query:String):Boolean

// get the number of records returned from the most recent query
mdm.Database.SQLite.getRecordCount():Number

// get a field from the most recent query
mdm.Database.SQLite.getField(rowIndex:Number, columnIndex:Number):String

// returns the result of the query as a [2]-dimensional array
mdm.Database.SQLite.getData():Array

// get the most recent error in text form
mdm.Database.SQLite.getLastError():String


And that's it. Pretty braindead, actually. You can't even open more than one database at a time, not that it's a problem for me.

Digging into the SQLite API last night, the whole thing is basically a matter of the glue-DLL passing along query results to SQLite, then storing those results into a dynamic 2-dimensional array of strings, passing those values along to the caller, and wiping out that array when a new query is run. The only function that's remotely complicated is getData, because that returns data as an ActionScript array. That function can be written entirely in ActionScript as a combination of getField and getRecordCount, so not much problem there.

Yeah, it looks a bit hairy for a high score table, but I figure it'll be good to have some decent small/portable data handling in my future apps.

Yeah, I'm writing tools. I try to avoid it when I can, but I just don't see another solution that's even remotely as elegant.

Now it's just a matter of actually writing it. I'll have to start on Monday. I'll probably just write it in C. If the whole mess comes to more than 10k, I'll be disappointed with myself :)

Wednesday, April 12, 2006

Yep, it's a two-fer

Okay, between Rick (rcarey1) and Emmanuel Deloget, I might have a solution to everything.

Rick and I IM-ed a bit, and I think I have a design solution I like.

First a quick screenshot to give you a frame of reference.



This is the first screen you see when the game starts. It's pretty simple, but has everything you need to get started.

Solution for the design

The cute little scrolling box you see here will no longer contain the highest scores. Instead it will contain the scores for the most recent 20 (or 50 or 100 if it loads fast enough) games you have played in the order you played 'em. It's not really all that informational, but it'll give you a feeling if you're "on a roll" or not. After 20 (or 50 or 100) games, the oldest games will start dropping off the bottom of the list.

(I'm also gonna get rid of that "name" field. No point in making users log in to their own game)

I'll also have a second array of one byte per board. For the sake of design, let's assume that it's an array of a million boards (and hence a million bytes). The array will be initially populated entirely with 0xff's, which signify an unplayed board. After you play a board, the game will replace that byte with your actual score.

For example, the first time you play board 813211, it'll look up cell 813211 in the array. Seeing a 0xff, you'll get a little message on the game screen saying "you have never played board 813211 before". Suppose you get the game down to 76 pieces then give up. It'll now store a 76 in byte 813211. If you ever happen back to board 813211 again, your message will state "You have gotten down to 76 pieces on board 813211. Try to beat that!". If you manage to do better than 76, it'll replace that byte with your new score.

I think this is a "best of all worlds" situation without getting so complicated that it scares away casual players.

- If you just wanna play the same board over and over and try to get the highest possible score for a board, it'll keep track of your best score.

- If you wanna ensure that you never play the same game twice, you'll have an indication of that.

- And if you're just a casual player who doesn't care at all about any of that, you can just gaze at the "most recently played games" table on the front page and marvel at the great scores you got recently.

Now then. . .

Solution for the practicalities

Emmanuel Deloget mentioned that MS Access databases can run from a DLL and don't have to run as a separately-installed background process like MySQL, which is a fact I should've been able to glean with about five minutes of thought.

I have MS Access, so making up an MDB file isn't a problem.

MSJet40.dll compresses to about 650k. That's bigger than SQLITE (which compresses to about 100k), but it's not so heavy that it'll scare downloaders away.

One problem. I can't find anything with the particulars of licensing and packaging and installing the MS Jet DLL(s). This'll need to install on your grandma's machine without any fuss, so I need to figure out all of the particulars as far as licensing (if any), installing (if anything more than copying the msjet DLL to your app's directory) and registering with the system (if required) that I'll need to do.

Anyone know of a resource for the Jet DLL runtime particulars?

Thanks for the dialog

Big thanks for all of the comments yesterday. It's all really valuable and I'm taking it into account.

Wow, it's almost like we have professional seasoned game-design types here and not just a buncha teenaged kids who are only after the latest kewl frag-fest. I once again wish death on the Gamedev Lounge forum :)
Two other facets of the design that I need to detail that will certainly affect the process. . .

Fact one

Perfect scores in Shi Sen are rather commonplace. Unlike something like Voracity (where perfect scores are nigh-impossible), it's not all that difficult to "beat the game". Much like the standard Mahjongg/Taipei/Shanghai game, it is possible to make a configuration of tiles that's impossible to beat, such a configuration doesn't happen very often with a random tile placement.

In casual play (i.e. without a helper-bot), I'd guess that the odds of me being able to get a board down to zero tiles is about 1/6. Only a bit more difficult than the "classic" Mahjongg puzzles.

Hence, I don't think that having a separate table of perfect scores will work. Even Klondike (aka Windows Solitaire) wouldn't need such a "ring of honor", and the odds for beating that are about 1/20. It's either all or none with the perfect scores.

However, I'm now leaning towards only storing perfect scores from a usability standpoint. Much like Klondike, with a little play you (or at least I) take a "win-lose" attitude. In Klondike, if you place all of the cards and get the little bouncy animation, you win. Anything else is a loss, no matter what the little score display in the corner says.

I think that users will roll their eyes if the system brings up a "Good job, enter your name in the high score table!" if they're stuck with 98 tiles remaining on the board. That'd be like Windows Solitaire saying "You can't place any more cards. Enter your name for the high score table."

Fact Two

This is a technical limitation. I'm using Flash for the games and a tool called Zinc to make the Flash apps look and act like first-class apps. One thing Zinc provides is a way for Flash apps to open and save files (like high score tables) to the user's hard drive. Flash itself has no file functionality for obvious reasons (or if it's not so obvious, it's so I can't write a web page ad that overwrites files in your Windows directory if you don't want to buy my V1aGr4 knockoff).

That being said, Zinc's file save-n-load is rudimentary.

Really rudimentary.

Specifically, two functions. . .

mdm.FileSystem.saveFile(filePath:String, dataToSave:String):Void

and

mdm.FileSystem.loadFile(filePath:String):String

So basically if I call loadFile, it stuffs the entire contents of a file into a String that I can then parse and massage at my leisure. Once I've made any changes to that string, I can write the whole goldurned thing back out.

And that's pretty expensive if that file wants to get big, both in memory and disk access. Zinc does have database access, but that's even more unruly, as it requires an ADO, MS Access, or MySQL data source, which is way outta line for a casual game.

A little no-install-required database like SQLite would solve that problem in a jiffy, but that'd require me to write some glue-code in C to bridge between SQLite's sophisticated functions and Zinc's rudimentary methods for talking to DLL's.

And that'd stretch the schedule. Especially since I haven't written a line of C in years.


Compromises compromises.

Tuesday, April 11, 2006

Musing out loud.

Working on the standalone daily puzzles (which need a catchier name than that). I have a design issue, though.

Let's take the Shi Sen puzzle. In it, you have one million possible boards (it's just a random seed, so don't get impressed). After you play a game, it logs the following into the high score table:

Your name, board number, time, and number of tiles remaining.

If you play a particular board (say board 1000) and solve it with fewer tiles than you did the previous time you played board 1000, then it'll replace that entry on the table with your new score. If not, it'll tell you that you already got a better score on a previous play.

These entries are stored in an XML file.

The problem is gonna be size. If there are one million (or ONE MEEEELION) boards, and you play two or three games a day during coffee breaks, that table and XML file are gonna get big and slow. And, having seen my target audience, these are games that people leave on their machines for YEARS, so the potential is that the table will get so huge that the game will either crash trying to load it or will get so slow with the saving and loading that you won't wanna play it.

The solutions seem to be:

- Make the number of possible boards smaller, like 1,000 or 10,000. While it'd be a marketing hit that you wouldn't have as many possible games, the practicalities are that you will never pop up a game and immediately say "Hey, I remember this layout".

- Keep the big number of boards, but throttle the size of the high score table to 200 or so entries, throwing out the worst score in the table when you make a better one. While this does fix the practical part, it does diminish the potential of saying "hey, let's see if I can get a better score on number 1000 than I did yesterday, as yesterday's score might not even be there for you to see.

- Only keep scores for boards where you eliminated all of the tiles. While very good players could still conceivably "clog the board" if you play the game constantly, it'll fill up much slower.



As an example, I'm looking at my favorite wargame, Slay by Sean O'Connor. Similarly to my games, it has 10,000 "islands" to defeat. The high score table only stores the 20 best entries (shortest number of turns before the enemies surrender) and does replace entries that are "on the board" if you beat 'em in fewer turns.

The difference, though, is that Slay doesn't have a true "perfect score". While there's a practical limit as to how few turns you can make before losing, there's no real concept of a perfect game.

Shi Sen, OTOH, has a perfect game. If you eliminate all 144 tiles on a board, you have played a perfect game. You can never do better than that.

I asked Shelly, and her response was to do whatever's least obtrusive because she uses the game as an executive time-killer and has no desire at all to ever try to beat the same board with fewer tiles and/or a better time. And, honestly, that's probably what I'll be dealing with for most of my audience. The competative types aren't gonna be playing my games. They're certainly competing in the Daily Puzzle arena, but it's about the most casual kind of competition you can imagine. We're talking anonymous 24-hour turns here :)



My current solution's gonna be a melange of all of all possible solutions:

1. Reduce the possible games to 10,000.
2. Throttle the high score list to only 100 or 200 entries, depending on performance.

I was gonna only store scores for perfect games, but doing so really won't affect performance. Non-perfect scores will be shoved off the board by perfect ones eventually, so there's not really a hit for having non-perfect scores other than the board will hit the limit sooner.

Thursday, April 06, 2006

Coming out of the closet

After coming to terms with myself, I have decided to embrace an alternative lifestyle. Please be understanding.

The Lion, The Witch, and the Bigass pile of Coffee

Here's a good deal if you've got an Albertsons grocery store nearby (mostly western US).

The deal is this. If you order groceries online, they have a $25-off-$50 coupon code. Also, you can get $15 off if you buy the Narnia DVD and a pile of Proctor & Gamble products.

1. Go to albertsons.com and set yourself up for home shopping.
2. Click the big "Narnia deal" button at the top.
3. Add the Narnia video to your cart.
4. Add 2-pound cans of Folgers to your cart ($5 each if you have a shopping card, apply for one if you don't), until your total is over $50. There are other things that count too, like frozen Minute Maid juice and bottled water.
5. When you check out, ask for store-pickup ($5 surcharge).
6. Enter the coupon code "SpringFifty06" for $25 off your $50 order.

Your total should now be $50 (video and items) - $25 (coupon code) - $15 (narnia discount) + $5 (service fee) + tax = about $17.

I ended up getting four cans of coffee and four 10-packs of juice boxes and the Narnia DVD for $17. I'll probably ebay the video for ten bucks, thus giving me eight pounds of coffee and 40 juice boxes for seven bucks.

It's just plain Folgers, which isn't the best coffee. Their French Roast is pretty good, but that wasn't in the deal. I usually mix the Folgers with better coffee (ground bean or Melitta), which is pretty good.

If you need more info on the deal, go here.

Wednesday, April 05, 2006

Boot Camp = who cares

The new Apple machines can now multi-boot XP and/or have an XP partition on the hard drive.

Free clue: unless you have very special needs (like you're a developer deploying on multiple platforms), multi-booting different operating systems is too clunky for words.

Me: Okay, I finished writing and spell-checking a spreadsheet of earthwork calculations in my superior-to-Windows spreadsheet app on my Mac. Now all I need to do is paste the text into AutoCAD so that it'll print up with the rest of my stuff. Of course, AutoCAD only runs on XP, so I'll need to save my file out in an XP-capable format, save it on a key drive or a server because the drive formats are incompatible, shut down my machine, restart it in that inferior XP operating system, load the file, copy it to the clipboard, and paste it into AutoCAD. That should take ten minutes tops.

The bottom line is this. . .

Fact 1: The new Apple machines were always intended to be able to boot XP. There's a reason why it took approximately three minutes from the machines appearing on peoples' doorsteps to some kid getting XP running on one.

Fact 2: OS X was always intended to be able to boot on generic PC hardware. Apple has had betas of Intel-capable OSX out for months. After people got OS X booting on non-Apple machines, Apple made approximately zero effort to prevent it from happening when they went gold.

Now then, if you're gonna argue that Apple's all about ponytailed openness and isn't about securely marrying their hardware to their software, I say HA! Apple has ALWAYS worked hard to lock specific OS's into specific machines. The first thing MacOS has always done when it boots is to figure out what kind of machine it's running on and see if it's even allowed to boot on that machine. Whether it's done so that you'll get the best possible user experience by not running a pig OS on an underpowered machine or (more likely) to get you to buy new hardware is irrelevent, the fact remains that Apple has always worked hard to ensure that their OS will only boot on the machines that they want it to boot on.

But when it comes to OS X for Intel, they're suddenly caught twiddling their thumbs when they discover that any kid with a Dell can boot OS X on his machine?

Not a chance.

Fact is, Boot Camp is a stop-gap. A kludge. In the future, Apple's gonna come out with the following:

- A virtualization program that'll allow you to run XP apps from within OS X. Whether it works as a standard machine emulator (like Virtual PC or VMWare) that runs all your Windows apps in a box or if it's a bit more integrated like Apple's "blue/yellow box" solution of running pre-OS X apps remains to be seen. But you will be able to run XP apps directly on your Mac, including things like clipboard support.

- A virtualization program that'll allow you to run OS X apps from within XP. Whether it works as a standard machine emulator (like Virtual PC or VMWare) that. . .etc etc etc.

Both of those things are gonna happen. It's inevitable. And if Apple don't do it, someone else will. And then multi-booting between XP and OS X will fade away like all kludges do.

Monday, April 03, 2006

Fix yer active content.

Read this, because this is important if you run a web page.

If you have any "active content" on your webpage that loads from an APPLET, EMBED, or OBJECT HTML element, your page is gonna act funny in the upcoming version of IE.

Now then, before you jump on the "IE Suxxorz" bandwagon, it ain't Microsoft's fault. Basically some guy managed to patent "active content" items in web pages that load from an external file via the aforementioned tags. That means that Java applets, Flash applets, Shockwave movies, Quicktime movies, Virtool applets, and a buncha other embedded apps are affected. Things that aren't embedded from external files, like menus written in javascript, are unaffected.

I don't know if or how this'll affect future versions of Firefox and/or Opera. The patent-owner, Eolas, might just be going after the deepest pockets first.

The upshot is that, to comply with the patent, active content in web pages on IE 7 must be activated. That means when you click on an active webpage element, it'll pop up a tooltip saying that you'll have to click it again to interact with the content as shown here. After that, the applet will work normally.

Stupid? Yes.

Pointless? Yes.

Annoying? Yes.

Easily worked around? Fortunately yes.

Apparently one thing not covered by the patent is putting those common embedded tags in javascript rather than HTML. So if you do a little tweaking to your HTML, you can ensure that your content will continue to work fine on everything.

If you're using Flash, an easy little hack is here. It works just fine in every browser I tried and adds a few little niceties like player version detection.

If you're running Java applets or Shockwave or something else, google around for a similar hack.

Also fortunately, wrapping your applets this way is reasonably future-proof. If an industry consortium appears and crushes this patent like a bug, you won't have to return to pull all of your workaround code out.

I just did it with all of my stuff, so if you see any of my pages suddenly acting funny, lemme know.

Just FYI.

Sunday, April 02, 2006

Whole lotta weekend goin' on

Yikes my kid had herself a weekend. On Friday our school had "date night", which is a party that kids can attend while parents go elsewhere. Maggie had pizza and played party games until around 10 pm while her parents went to see "Slither" at Movie Tavern.

Really fun movie, btw. Doesn't take itself seriously for a single frame. Corman would be proud.
Saturday morning, Maggie had a Pump It Up Party for one of her buddies. Later that afternoon, we met up with R, T, and D to go to Six Flags in Arlington. We recently got season passes, so it's nice to take advantage of 'em. The kids had a fine time, but both of 'em were the living dead by the time we finished. It was cute watching 'em on the kiddie rides.


R insisted that I will blog about what a value I'm getting on my 6F season passes, as I'm irrevocably drawn to do so. I didn't really feel the pull to do it originally, but what the heck.

Problem is, the season pass is such a maze of gold-versus-silver passes and parking passes (which you need because it's $15 to park), so I'm gonna do it this way (inc tax). . .

Shelly's pass - $81
Maggie's pass - $81
My pass - $91 (I got a gold pass, as it has a 25% discount on food and park-stuff, which we may never use because it's five bucks for a friggin' ice cream cone! Anyway, we figured we'd just need one of those, so we upgraded mine)
Parking pass - $50

total - $303

Number of person-visits as of 4/1 = 6 (two visits for the three of us)

Per-capita price for a visit to Six Flags = $50.50


Now then, we just need to visit 6F a couple-dozen more times by the fall, and we'll get the price down to less than a visit to the McDonald's play-land :)

R, T, and D bought passes last night, so we'll probably have plenty of opportunity over the summer to drag the kiddos over for an afternoon at the park.

The food's a friggin' fortune ($8 for a really insipid spongy microwave pizza in the food court). My biggest worry was that Maggie was gonna be a pain about food, because there's someone selling cotton candy and/or popcorn ($6 each) about every three feet. Thankfully, she's so enthralled with the rides that the expensive snacks didn't even enter her reality-bubble.


I just need to remember to avoid eating badly, because it's a golden opportunity to do so. If I'm a smart person, I'll just grab a yummy healthy Subway sandwich on the way to the park and eat it at the picnic area in the parking lot. There's plenty of walking in the park (some of it with a kid on your shoulders), so it should be reasonably good for me, as long as I remember to eat well and bring along a water bottle.

We did well at the park, but then went to "On the border" afterwards, where I ate entirely too many chips w/guacamole along with my burrito and margarita. And I had indigestion and was miserable most of the night.

Ugh, gotta curtail that. It's Subway sandwiches in the picnic area next time.