Skip to content

Thief Level : Week 2

This week I spent a little while considering the backstory of the level, and now have at least a rudimentary scenario: Garrett the thief is taking an opportunistic foray into the local Shope of Curiosities, having heard that their prize exhibit, the McGuffin of Antioc, has been removed from its high-security public display, in order to be cleaned or maintained somewhere on-site.

On top of this, I’ve been refining the layout of the museum building, starting with the two-storey entrance hall, complete with a balcony running round it:

sketch of museum's two-storey main entrance hall

Plus, I’ve been planning the possible routes a thief might take to get from one room to another. Generally, the conventional paths – in through the main entrance and up the stairs and down the corridor – will be blocked by guards. So the player has to clamber up the outside of the building, explore the roof, dangle from a rope, pick a lock, find a key in the janitor’s quarters, which opens all the windows, and ledges outside a couple of windows lead somewhere interesting, etc.  I don’t want it to turn into a key fetch quest, but at the same time, I don’t want the player to be able to simply waltz all through the whole building. I’ve tried to engineer a single interesting primary route through the building, with the possibility of a few minor variations so players feel like they can exercise some freedom and decision making.

sketch of ground floor

Having done all that, I’m now quite happy that my plans are sufficient to produce a small but adequate level. I’ll aim to get that complete, and any fancy window dressing I can layer on top will be a bonus.

I completed the modelling of all the rooms in the building, and doorframes inbetween them. I applied some quick floorboard textures to differentiate the floors and ceilings from the walls. Here you can see the view from the main entrance, looking into the two-storey entrance hall, with the balcony around it visible up on the next level:

main entraince with floorboards

And the view while approaching the top of the stairs, looking down over the balcony. There will be a railing when it’s done:

Approaching the top of the stairs

Thanks heaps to Qolelis for a comment with a tip about textures on stairways, to rotate the texture 90 degrees on each stair’s vertical rise. I only just saw that, but will definitely apply it this week.

Update: I feel a bit self-concious that I’m creating the bare minimum that could qualify to be a Thief level. There is not yet a lively, engaging backstory to the level, complete with colorful characters, cleverly intertwined with the canon of the original game.

Similarly, the mechanical contents of my level are as simple as possible. I haven’t stretched myself, thinking of imaginative locations or motives for Garrett to explore. I do not plan to have any clever special objects or custom scripting in my level, defining dramatic changing mission objectives as the player reveals new information. It’s a very straightforward ‘get into a building, steal the loot, and get out’.

Partly this is very deliberate – I want the level to be as minimal as it can possibly be, so as keep it achievable. But also, this is partly in response to my feeling that being creative is hard, especially when under pressure. Right now I feel as though I have enough to worry about just getting to grips with the minutia of the level editor. I almost feel as if I need to become comfortable with that before I can relax enough to get creative with it.

This isn’t entirely unexpected. Clearly one cannot do great work on one’s first attempt. But at the same time, I don’t want to just ‘give up’ on the creative aspects. I want to do as good a job as I can do, under the constraints of a small, straightforward ‘first time’ level done in a reasonable timeframe. So maybe I just need to keep iterating. Embelish the dramatic backstory little by little, see what occurs to me as I go on. Look for some flash of inspiration as I bury myself in the process. Fair enough. Baby steps.

Update 2: I created a quick TODO list, as a first approximation of how much work there is to be done. I ended up with a list of 67 mandatory items (eg. Add doors inside each door frame; First pass at lighting; Add balcony railing.) In addition I have 18 optional items (eg. Add carpets and rugs; Hide moss arrows in the garden; Entrance hall main exhibit.) The screenshots above represent about six completed items (eg. Dromed tutorials; first floor rooms; doorways and arches between rooms; staircase.) So at the current rate, it’s roughly 28 weeks of work, which is double or triple what I’d planned on. Hopefully my rate of completing items will increase substantially as I get into the groove. I’ll have to monitor this going forward, and slash scope if I can’t drastically accelerate.

Howto bundle binary dependancies with py2exe, et al.

Hey. I notice that py2exe-users has a recent question that seems to be about how to correctly bundle the required Microsoft C runtime DLL with executables generated from Python scripts.

Last month I updated the py2exe wiki tutorial to cover this issue, as best as I was able. Since people are still asking questions about it, I figured I’d promote that change a little.

Check out the new, revamped py2exe tutorial page!

That is all.

Creating a Level for Thief 2

After Sinister Ducks, my videogame creation mentor suggested that I create a mod for an existing game, in order to distance myself a little from the programming aspects of creating a game, and instead spend a little time considering the gameplay and the art and the music from the perspective of the user. Sounds like useful advice.

So, the last couple of weeks I’ve been working through the tutorials for DromEd, the notoriously cranky level editor for vintage sneak-em-up Thief: The Dark Project. (Specifically for the sequel, Thief 2: The Metal Age, which has a slightly improved engine and editor.) I chose this for three reasons:

  1. Released in 1998, Thief is old enough that the assets are simple low-fidelity geometry and bitmaps. These are easy enough for me to create and edit, plus if I intersperse existing game assets with my own shoddy creations, there won’t be a tremendously jarring disparity in apparent quality.
  2. Even though Thief is ten years old and the company that created it long gone, there’s still a thriving community of amateur afficionados, churning out new missions at the rate of several per month, many of which are of exceedingly high quality – in some cases exceeding that of the original game. I’ll be in good company, will have some meaningful feedback, and will have forums to turn to when I get into difficulties.
  3. Last but not least, Thief is one of my favourite games of all time. The emphasis on sneaking around and avoiding confrontation suits my sensibilities. Your protagonist, Garrett, is a marvellous, mercenary character. Best of all, in Thief 1, it reveals unexpected depth halfway through – the player’s expectations of a succession of simple heists takes a strange twist when the powerful storyline reveals itself.

Having finished the tutorials, this weekend I broke ground on creating my own level, or ‘fan-mission’ (FM), in the parlance:

Designing a Thief2 Level in DromEd

I’m using the DromEd Toolkit, which is DromEd with some third-party patches and bugfixes applied to it. My first impressions with DromEd are that it’s very clunky and ugly, and startlingly lacking in documentation. I’ve taken to dipping into the configuration files to see what keyboard commands exist to experiment with. There are a bewildering variety of binary patches to modify the executable in various exciting ways, and forum posts about it, although helpful and prolific, seem fragmentary and rife with broken links. I’ve still no idea whether I ought to be using Dromed Delux instead, nor where I should get that from. It’s a glorious chaotic riot, and it’s a little intimidating.

Still, having said that, the binary patches have all worked fine for me, and the more I use the editor, the more it’s starting to grow on me.

I’m setting my FM in a museum. There’s already an existing museum mission out there, but as opposed to its marble-halled austerity, I’m imagining this will be more like the cramped, cosy, wood-panneled chaotic collection of something like the wonderful Sir John Soane’s Museum in London.

So progress as of week 1 looks like this: I’ve carved out some very basic geometry to form a stocky museum building. Here you can just about make out a hole in the brick facade that will form the front entrance. This is not the entrance that the player will likely be using:

This is all very crude thus far – with repeating textures on large surfaces, and plain uniform lighting. There are a complete set of mostly rectangular ground-floor rooms, with interconnecting doorways. The highlight of my modelling to date is this stairway leading up to the (otherwise nonexistant) next floor.

I’m not so happy with the wood texture I chose – I’ll go back and look for something more uniform. But I am happy with the way the stairs flair out at the bottom. I realised in the process of creating this that this makes it possible to fit a flight of stairs into a smaller space than would otherwise be possible, by allowing the bottom few steps to gracefully project out into the corridor.

Having finished this last night, I then dreamed about geometric operations on three dimensional spaces, which I think is a good sign.

Musicians : wake up!

I left this as a comment somewhere else, in response to someone complaining about how:

“…musicians are asked to just get over the fact that no one pays for music… [it is] my hope that someday more people make the same realization that unless people to help finance records, you’ll never get that fantastic song you can’t stop listening to all summer.”

Hey there. I really disagree that the onus is on the rest of society to solve all musicians’ problems. People have been copying my work on the internet for decades now. I’m a computer programmer. We’re in exactly the same boat as musicians – probably more so, and have been there for longer. But we manage to get by.

Some programmers attempt to stop copying of their work, but this is rarely successful. Others take a different tack. We’ve had to adapt. We acknowledge that our work will be routinely pirated on the internet, and we adopt our business model accordingly. We have to make and sell different sizes and types of tools than we were accustomed to making, and sell them through different channels. We have had to find other ways of charging for our work. My own company gives away our software for free. We embrace piracy as inevitable, and use it as a promotional tool.

This is difficult. It is counter-intuitive, grounded as we all are in the scarcity economy of the physical world. It requires us to change our attitudes and outlook and behaviour. Sometimes we fail. We are still figuring out the realities of our markets in a post-internet world.  But goddammit we are trying and sometimes we try things and they work. The software business is more diverse and thriving than it ever has been – despite all our work being just as freely copyable (and freely copied) as music.

The financial hardship that musicians are feeling has always been felt by musicians. Copying music on the internet has not made this any worse than it always was. This is simply the cost of choosing to be a musician.

Musicians must adapt, just like programmers have. It saddens me to see so few musicians even try. Is it really true that computer programmers are more flexible and adaptable and imaginative than musicians. Who would have thunk it?

Embracing piracy as a promotional tool can allow bands to make more money on live shows than they have ever made selling records, but still, the majority of musicians sit around, complacent, thinking that the responsibility lies on the rest of society, to put things back the way they were before the internet.

No. I for one refuse. Adapt or die – if you can’t make it, someone else will take your place. By definition, that someone will be more adaptable, imaginative, risk-taking and dynamic. Isn’t that supposed to be what our creatives are good at?

People will doubtless think I’m being harsh – imposing my tyranny on struggling musicians. But I’m not. When I say “adapt or die”, I’m not imposing my will. I’m merely reminding you of reality. If we were talking about a guitarist who couldn’t play the guitar, we would all agree that they have put themselves in a bit of a paradoxical situation, and that they must either adapt (learn to play) or die (stop being a guitarist.)

This is how competition works. Competition might seem harsh, but it’s best for everyone in the long run. The poor guitarists are eventually persuaded by market realities to stop being guitarists and try being something else. The good guitarists get rewarded, and the standard of music available to the world is increased as a result.

Instead of untalented guitarists, today we are talking about musicians who would like to get paid, but who don’t want to expend any energy on figuring out how they will get paid. Can you see the paradoxical situation they have put themselves in? This attitude is entirely understandable and human – I also would enjoy locking myself in my room and making beautiful computer programs which nobody else need ever see. But if I expect to get paid for making computer programs, then I must interface with the reality of the world around me. It’s no use me simply wishing that High St stores will start selling my software in shrinkwrapped boxes again – those days are long gone. Instead, I must figure out what programs people want, and produce them in a timely manner at high quality, promote them somehow, and figure out my angle on how I’m going to get people to pay.

It is not too much for us to ask musicians to also have to conform to reality like this. If they want to make money, and the means of making money from music are changing, then they will have to expend a little energy figuring out how they are going to get people to pay. If they don’t want to think about that at all, then fine, they won’t get paid. Adapt or die, we’ll all be better off for it.

MSWindows Programming : Propogating child process exit values out of .bat scripts

“God dammit. Why won’t you just DO what I WANT you hopeless pile of crap!”

So goes the refrain. I think you know where I’m coming from. Yet again, I have ended up learning far more about crappy DOS scripting than I ever wanted to know.

So I’m writing a program to automate some small task on Windows. One of the jobs of this tool is to modify the current environment. But I don’t know how a child process in Windows can modify the environment of it’s parent (namely the command-line shell that invoked it.) Can it be done?

So I hack a ghastly workaround: Wrap the script in a .bat file. A .bat file is invoked from the command-line in the same process as the shell, so any change it makes to the environment are made to the environment of the invoking shell itself. This also has the advantage that the tool can now be invoked by typing ‘toolname’, just like on other platforms, as opposed to ‘toolname.py’ or even ‘python toolname.py’. So I wrap my Python script ‘toolname.py’ with a new file, ‘toolname.bat’, living in the same directory:

:: first run our tool
python "%~dp0%~n0.py" %*

:: then make any changes to the environment
set THIS=THAT

The %~dp0 and %~n0 gobbledygook is a batch file way of referencing the same drive, path and filename (minus extension) as the current script, to which I add ‘.py’ to run toolname.py. Easy enough.

There’s a minor problem: The environment changes that need to be made depend on what goes on inside toolname.py. So I have that Python write a new batch file to the temp directory, containing all the ’set’ commands which will replace the hardcoded  ’set THIS=THAT’ in the above script. Then we call that new temporary bat file from here:

:: first run our tool
python "%~dp0%~n0.py" %*

:: then make any changes to the environment
call %Temp%\%~n0-setvar.bat

Which is good enough. Presumably it will barf all over the place if run concurrently. But there’s a more pressing problem. I need the exit value of this tool to be equal to the exit value from toolname.py. Currently, the exit value of this .bat script is always zero, because the ‘call’ command at the end is always successful.

One solution I’ve seen used is to remember the exit value from toolname.py, and then use the DOS exit command to propagate this value out to our caller:

:: first run our tool
python "%~dp0%~n0.py" %*
set EXITVAL=%ERRORLEVEL%

:: then make any changes to the environment
call %Temp%\%~n0-setvar.bat

exit %EXITVAL%

The problem with this is that ‘exit’ doesn’t do what you think it does. It doesn’t just stop interpreting the current script, rather it terminates the current interpreter, ie. the shell that is running the script. If you run this from a command-line, since Windows doesn’t differentiate between a console and a shell, your window disappears. Sigh.

The exit command has a fix for this: It takes a switch ‘/B’, that causes it to just end the current script, rather than killing the shell. But now, it ignores any %EXITVAL% parameter you try to feed it, so the exit value of your batch file is always zero.

This is what I get for developing software on Windows. Nothing ever works the way it ought to. It’s as though everything were designed to oppose simple engineering idioms, like composing systems out of small, interchangeable parts.

So here’s what I finally did. The exit value of running a batch script can be set without using the hopelessly brain-dead ‘exit’ command. It is equal to the exit value of the last process the script invokes. So instead of exit, simply find a process that will exit with the value you need, and invoke it as the final command in your batch script:

:: first run our tool
python "%~dp0%~n0.py" %*
set EXITVAL=%ERRORLEVEL%

:: then make any changes to the environment
call %Temp%\%~n0-setvar.bat

:: and propagate the exit value to our invoker
python -c "import sys; sys.exit(%EXITVAL%)"

Bingo. I now have a Python process that can modify the environment of its invoking shell, and propagates the correct exit value out of the wrapping DOS script. [Short bow. Applause. Roses. etc.]

My Fonts Look Crap. I blame Windows and ATI.

I know, I know. But I use Windows for 8 hours a day at work. So what do you do?

Here’s the poster-boy for programmer-friendly fonts, your friend and mine, everyone loves him, Inconsolata:

(Update: I evidently have some javascript or CSS trickery that squashes these images horizonally if your browser is narrow, to make them fit in the window. Since I’m banging on about microscopic differences between microscopic fonts, then if you’ve got this far you probably ought to make sure your browser window is wide enough.)

inconsolata-11

I don’t know about you, but to me that looks unutterably crap. Wonky and irregular. On the right of the orange line is what it looks like with ClearType turned off. Meh. Presumably I’m doing it wrong, somehow, but unless I figure out how, Inconsolata can fuck right off.

So then I fire up the trusty fallback, Consolas:

consolas-10

This is better, certainly, but the letters look cramped. For the number of visible lines in a window that size, the letters are awful small. Again, on the right of the line is ClearType turned off – which in this case distinctly worse.

So I continue peering at a succession of monospaced idiocy, eventually ending up on DejaVu Sans Mono:

deja-vu-sans-mono-9

This still isn’t perfect, but it’s the best I can find. Note that it bears out my impression of Consolas being cramped – even though the letters are substantially larger, we still manage to fit an extra line of text in. This time, turning ClearType off (right of the line) makes it a little crisper, and a little more wonky, but not much.

This isn’t just in Vim. It looks like this in all applications. I’ve tried running the ClearType Tuning Powertool, to no avail. Admittedly, all these fonts start to look a damn sight better when I increase the size a few notches. But that’s bugger all use really, isn’t it? Maybe I should be digging out some mono fonts designed especially to be viewed at small sizes? Oooh, now that’s actually not a bad idea: How about those Android fonts everyone’s banging on about? Droid Sans Mono:

droid-sans-mono-10

This isn’t bad, but does contain all the old ‘zero vs upper-case O’ and ‘one versus lower-case L’ ambiguities. I think I’ll stick with DejaVu Sans Mono.

Does Inconsolata work OK on Windows for everyone else?

Update: Gerry suggested trying out Proggy Fonts (thanks!). These are bitmap fonts (unless you want to do without extended characters) so they won’t scale. Nevertheless, here’s how some representative fonts from there look. First up, Proggy Clean slashed zero:

proggy-clean-sz font

I love the crisp clarity of a pixel-perfect bitmap font with no scaling or anti-aliasing. On the downside, I have a feeling that the characters’ shapes aren’t quite as well-formed and beautiful as DejaVu. Not sure whether or not this would bug me. Next up, Proggy Opti:

proggy-opti font

Color me impressed. Opti still has the wonderful pixel-perfect clarity of Proggy Clean, and manages to fit four extra lines of text into the same sized window. Obviously in order to achieve this, the characters are smaller than Deja Vu, but this is no bad thing. I would have liked to scale Deja Vu down a tad from the size you see it above, but if I try, the letters start to become a little distorted and indistinct. I might well give Opti a spin for a few days, see how it wears on me. Thanks for the suggestion Gerry!

Sinister Redux

A few months ago, Glenn and Christian and Menno and myself created Sinister Ducks, a game with some quacking, for PyWeek 9, a contest to write a game in Python in a week. It plays a little like a simplified version of the arcade classic Joust – press fire to flap. When birds collide, the highest one wins, while the lowest one sheds feathers and plummets to the ground.

Since the competition, I’ve been polishing and refactoring for my own edification in odd hours here and there, and I’m pleased to declare that process finished. Behold, Sinister Ducks 1.0.2:

Sinister Ducks 1.0.2

Things I added since the competition include:

  • Fixed the game being so ridiculously easy that one could play it interminably
  • There are now lives, and an actual Game Over screen and everything
  • Completely reworked how the gameplay works in regard to attacking ducks and collecting feathers – our previous mechanic didn’t work very well. The feathers now temporarily boost a score multiplier, displayed top-left. Attacking other birds yields more points for successful chained consecutive attacks, without collecting any feathers along the way. But you can only get feathers in the first place by attacking birds. It’s your job to figure out the resulting best-scoring dynamic.
  • Understand and enjoying the scoring dynamic is aided with little floating numbers showing the value of each bird you defeat.
  • Enemy birds now come in larger waves as time goes on, and one or two of the sinister ducks are angry and fast.
  • The game speed is now scaled by the time between refreshes, so it now runs perfectly fine on slow machines or VMs that can’t make 60fps, or if your monitor has an unusual refresh rate, or even if you disabled vsync in your graphics drivers to yield hundreds of frames per second.
  • Refactoring and OpenGL performance fixes (those sprites are texture-mapped quads, under the covers.) so that it’s now massively faster than it should ever need to be. The refresh rate with vsync disabled on my own 5 year old lappy is about 400fps.

You can download a Windows binary to download, unzip and double-click. On Linux or Macs it should run from source code, if you can be bothered to install the dependencies first, as described in the README.

The game’s only website is its Google Code repository, from where you can download it.