Making Skyline: What’s not in a Game?

This game I’m building for the 40th anniversary of the Atari VCS … there are a few things it needs to “do.”

Back in 2007, I threw together a rather cute (IMHO) proof-of-concept adventure game called Skyline. As for game play … OK, well, it kinda … sucked. And it has been, thankfully, totally forgotten.

So let’s not do that again. The sucking part.

Now, I do want to show off the capabilities of the Atari — as well as keep the basic game portable enough to get it onto other systems. What “capabilities” are we looking at? The TIA (Television Interface Adapter) graphics are challenging, themselves, and using them effectively is obviously part of this. Like many games, I’ll “have to” use a certain amount of “flicker” for complex scenes, but I don’t want more than 30Hz flicker most of the time. I’d prefer not to have the Venetian Blinds effect, but I’m re-using the technique I’d used nine years ago, which combines a bit of flicker/jitter with the Venetian Blinds to hide it, and I’m OK with that. There should be an acceptable amount of music … I won’t demand “fully-scored,” but the music, when present, has to sound something like music should. There should be some sound effects.

Controller-wise, I’ll accept standard Atari joysticks with one button, but leave in support for Sega Master System or Genesis controllers, reading from two buttons when those are available. The console controls should work more-or-less as expected: Game Reset to start the game, Select can be used in-game for a menu feature, and the Color/B&W switch repurposed as a Pause control. (Except on SECAM Ataris, where there is no such switch.)

If someone actually happens to have a MemCard or AtariVox, let’s let them save games to it, sure.

If the program crashes through the BRK vector, it should display some kind of useful debugging info. At least, a sad face and a build identifier and probably a full core dump (the entire 128 bytes of RIOT RAM dumped to the screen).

For testing, I’ll want some cheat code vector or other, also.

It should run on NTSC, PAL, and SECAM systems, and the display should look as comparable as possible on each. That means not only using the platform palettes and timing standards, but also ensuring things like, the SECAM display won’t have things that turn “invisible” because of the limited (8-color) palette. (On NTSC, we’ll have 128 colors, and you can pretty easily read very light blue on very dark blue, but, on SECAM we don’t want to have that translate to blue-on-blue or something.)

So, what we don’t have and can’t use that we might wish for on a later system like, say, the Commodore 64, are:

  • We don’t have a lot of read-write storage. We’ll have to be thrifty about what we remember.
  • We don’t have a keyboard, nor a lot of input buttons.
  • We can’t put a lot of changing or moving objects on the screen at once, so we’ll have to be thrifty about that, as well.
  • Also, displaying text nicely is a pain, so we’ll need something for that.

Making Skyline: Part I: 40 Years of Atari VCS

It’s 2016, so we’ve have almost 39 years since the Atari 2600 was released. Let’s write a game for it.

Let’s write a game for a machine with 128 bytes (~characters) of memory, marginally “crap” graphics, and a 1 MHz processor. We’ll write it mostly in 6502 assembly language, and design graphics, sound effects, music, and dialogue. In order to get it to anyone, we’ll have to build cartridges with the game’s ROM and some control circuitry, build cases for them, labels, a manual …

Oh, and of course the 6507 CPU in the Atari is also used in a bunch of other computers from the 1980’s: The 6502 in the VIC-20 and Apple ][, as well as the Atari 400, 800, 5200, and 7800; the 6510 in the Commodore 64, the 8502 in the Commodore 128, the 2A13 in the Nintendo Entertainment System, all are more of less the same processor. The big brother 65816 is in the Super NES and Apple //gs. Totally different memory arrangements, of course, and different video hardware, audio systems, even input devices. Let’s try to produce a single game that’ll be playable on several of these.

OK, well, maybe it’s just me. But, while we’re at it, let’s design this on a modern Linux system with top-of-the-line development tools.

Here’s what I’ve chosen for starters:

  • The main editor for the program code is, of course, Emacs.
  • The toolchain that will compile the art, music, maps, and so forth into assembler-friendly data files will be in Common Lisp — and I’m not going to be too shy about being SBCL-specific, Linux-specific, or even Fedora-specific if it makes any difference. This tool is basically just for me, but if someone wants to use it elsewhere, they might have to do a little hacking.
  • For the tool, I’ll use CLIM for the interface. Restarts will appear in the CLIM Debugger, the CLIM Listener and Climacs will be available at build time, and if there’s anything that makes sense as a general-purpose tool, I’ll build it in CLIM as well. Among other things, this means that interactive building tools can use rich text and embedded graphics for their output cheaply. Nonetheless, it must remain possible (in the “no errors” case) to run a headless build and capture a reasonable (text only) log file output from the process.
  • The size of the build tool is unimportant, but I’d like it to run on a sub-$300 notebook without choking.
  • For graphics, we’ll use Gimp XCF files, but we’ll hack on Gimp a little. A Gimp (Guile) plug-in for exporting as PNG, and some palettes for Gimp to make it easier to hit the various color palettes of our target machines.
  • Atari gets first dibbs, followed by Commodore 64, and then we’ll see what else I have time (or interest) to build.
  • Music will be imported from General MIDI files, but I haven’t set my heart on any particular editor. In fact, it’ll probably mostly be Public Domain or Creative Commons classical music.
  • For maps, Tiled wins. Yes, I made a donation to the author, too. Eventually, my own Hath will probably replace it, as this project will probably eventually merge with Hath altogether.
  • Ideally, let’s write a scripting system that supports a reasonable subset of Lisp and writes out native 6502 code.
  • The assembly source files should be 64TurboAssembler (64tass) compatible.
  • The game needs to be runnable in Stella, Vice, and the like.
  • Ideally, anybody with Gnu Make and SBCL installed should be able to do a one-step build — so, it ought to be able to bootstrap the whole toolchain with DNF in some rational way.

So, some arbitrary choices I made up front, based on things I like to use or think are nice to work with.

So, now what? Oh … we need a game.

Let’s talk about that next time

Indenting even more nicely

I’ve been using this for some time, as I mentioned a few days ago:

(defun indent-buffer ()
  "Indent an entire buffer using the current syntax settings."
  (interactive)
  (save-excursion
   (global-trim)
   (goto-char (point-min))
   (while (re-search-forward "\t" nil t)
     (replace-match " " t t)))
  (indent-region (point-min) (point-max)))

With the massive re-indenting process that inspired that post, I came across the “need” to also re-fill comments (ie, reformat comments to fit within our in-house 120-character right margins) at the same time.

The resulting functions look like this:

(defun comment-forward ()
 "Advance the point to the next comment."
 (interactive)
 (skip-syntax-forward "^<!")         ; next comment-like char
 (cond
   ;; actually starts a comment; skip delimiter
   ((eql (face-at-point) 'font-lock-comment-delimiter-face)
    (skip-syntax-forward "<!"))
   ;; end of file
   ((>= (point) (1- (point-max)))
    nil)
   ;; not a comment here (maybe in a string or something)
   (t
     (forward-char)
     (comment-forward))))
(defun fill-all-comments ()
 "Re-fill all comments in the buffer"
 (interactive)
 (save-excursion
   (goto-char (point-min))
   (while (comment-forward)
     (fill-paragraph))))
(defun replace-all-tabs-with-spaces ()
 "Replace every TAB byte with a space."
 (save-excursion
   (goto-char (point-min))
   (while (re-search-forward "\t" nil t)
     (replace-match " " t t))))
(defun indent-buffer ()
 "Indent an entire buffer using the current syntax settings."
 (interactive)
 (global-trim)
 (replace-all-tabs-with-spaces)
 (indent-region (point-min) (point-max))
 (fill-all-comments))

The next step, of course, is to figure out how to nicely break up over-long code lines …

 

 

PS. That didn’t last long.

I replaced the use of replace-all-tabs-with-spaces with the nicer:

(defun strip-indentation ()
  "Replace   leading   whitespace   (tab/spaces)   in   preparation   of
re-indenting. Skips whitespace within comments or strings."
  (save-excursion
   (goto-char (point-min))
   (while (re-search-forward "^[ \t]+" nil t)
          (unless (member (face-at-point) '(font-lock-string-face
                                            font-lock-comment-face))
            (replace-match " " t t)))))

Dear Recruiter:

Dear Recruiter:

I want to believe that you’re trying to make the best of a bad situation. I know you’re probably not an idiot, but you’re probably not really experienced with hiring senior programmers.

I know, this post probably seems condescending or rude, but the fact is, we have been burned … a lot.

You probably know by now that programmers, as a rule, hate recruiters. That’s a pretty strong word, there … hate. The sad truth is, programmers are “in demand” in the job market, and for every five programmers out there, two of them are bad at it. But, they’re working, too … because for every five programmers, there are fifteen jobs available.

Seriously, go to Google, and type “Why do programmers hate recruiters?” Today, there are “[a]bout 628,000 results.” That’s just the tip of the iceberg. Your compatriots have set the bar really, really low.

Let’s make you a commission.

Your job is to find a good candidate, right? OK. First things first.

Step 1.

Find out what on Earth you expect us to do.

Seriously. Literally — I’ve counted this out before — I have gone through 58 e-mails from recruiters before finding one that actually mentions what the job is.

I know, I try to believe that you’re not an idiot, but that kind of basic stupid mistake is really hard to come back from.

Hint: None of these things count as a job description:

  • A bare job title like “Senior Systems Programmer” or “Mobile Application Developer.”
  • Names of products, operating systems, or programming languages: “iOS Programmer,” “Perl programmer,” Java, Linux, Apple, Lisp, …
  • A list of desirable skills or experience.
  • The name of some college degree or other.

Here are some actual job descriptions:

  • Develop a new operator control application stack for management of immersive (hardware/software) simulation devices
  • Implement the server side of a real-time, sports-based game
  • Develop an MMO-RPG game engine for thousands of simultaneous players
  • Develop back-end utility applications for internal maintenance of a shared, real-time data set
  • Develop embedded software for person-to-person communications with internationalization and localization to many language environments, including CJK languages
  • Create a web-based GUI wrapper to interact with a legacy mainframe application over the 3278 terminal interface
  • Maintain Electronic Data Interchange (EDI) software between a variety of trading partners using formats such as fixed-width EBCDIC records and X12N structured streams
  • Create Internet “chat” programs with web-based and VR-based front-ends
  • Develop multimedia, interactive presentations for WWW and DVD distribution
  • Develop software for high-volume printing press systems to streamline order proofing, production, and shipping processes

The job description should read like something that would appear on a résumé.

Step 2. At least pretend to read our résumé.

They’re longer than you’d like, I’m sure. Most senior developers have a CV section that runs on for a page or two, at least, and probably some skills summary stuff that goes on for another couple pages.

Read it. You might not understand all the tech terms, but at least you’ll have some hope of finding out something useful or interesting about us.

We are not your customer. We are your “victim.” Your goal is, of course, to hire programmers for your customer. That won’t work out too well if you haven’t even looked at our résumés. You might get the college kids with no practical experience, but you’re not going to get someone for a leadership rôle.

Step 2(a). Spell our names right.

You should be able to get at least that much.

PS: Trying to reference us on a first-name basis comes across as … smarmy. And, if you can’t correctly figure out what given name we use, it’s a bit of a red flag, too, isn’t it?

I’ve seen a Viet colleague get e-mail that mistakenly had her family and given names backwards (… since her family name, as is common in East Asia, came first). I routinely get mail with my given name misspelled or truncated, even though there’s a specific FAQ on my résumé “explaining” my name.

Step 3. Write a reasonable e-mail.

You want to reach a programmer? Great. Send an e-mail.

Don’t phone. Don’t even think about a phone call. Seriously. What if we’re at work? We’re sending you to voicemail, and deleting it without listening. Really. What if we’re at home? Same thing. We have caller ID. If you’re not in our phonebook, we push the big red ✗.

We all have e-mail. It echoes to our PC, our laptop, our tablet, our mobile phone, maybe our watch or something. We get your e-mail the second you sent it.

And we glance at it and read the first six words or so of the subject.

And then, we delete it or hit “reply with canned message → buzz off.”

Your only hope of getting that e-mail actually read is to get your foot in the door with that e-mail.

Make the subject memorable. “Can we talk?” is not it. “Urgent need…” is a turn-off. “Senior Developer” is not helpful.

Try cutting down an actual job description (see above) into about 5-6 words. “Game developer for FPS physics engine” is a good example.

Then, put your e-mail together like you’re writing a telegraph. Time is money, and we are probably reading your e-mail on a cell phone while we’re doing something else that is, to us, much more interesting.

Here’s a good template to work from:

Hello, Ms Susie Programmer; I found your résumé at <LINK> and I see that you’ve been working on firmware for some simulation and game devices.

I have a position here at CompanyCo. designing a new videogame system combining physical simulator systems with augmented reality components. I thought you might be interested. Some of the early press coverage of our prototype is here: <LINK>

If you might be interested (or know someone who would be) please drop me a note at your earliest convenience.

That’s about it.

HINT: do not paste some 5-line (or 20-line!) signature with a bunch of graphics. Seriously, that’s tacky.

That is about the most you’re going to get us to read. That’s the sort of pitch that actually gets good candidates to respond.

See Also:

http://blog.entelo.com/top-4-things-engineers-hate-about-recruiters

http://www.recruiterspam.com/

https://signalvnoise.com/posts/2598-why-are-technical-recruiters-so-clueless

http://business.stackoverflow.com/blog/2013/05/06/top-10-things-developers-hate-about-recruiter-emails-and-how-to-avoid-them

http://jasonpunyon.com/blog/2013/03/31/things-that-were-i-to-unfortunately-wake-up-tomorrow-as-a-recruiter-i-would-never-do/

https://business.stackoverflow.com/blog/what-developers-wish-recruiters-knew

Why Developers Hate Recruiters & What You Can Do to Change This

Why recruiting sucks

Death to Recruiters

Multiple keyboards, multiple layouts

If you have more than one (physical) keyboard connected to your Fedora box, with different layouts, you can load multiple key-maps at the same time.

Yes, technically, Gnome doesn’t permit this. The switcher in the GUI will reset you to one keymap whenever you log in, switch users, or put the machine to sleep. But, for a little inconvenience, you can get your layouts to work in parallel.

What I use is a little script named k that lives in /usr/local/bin. It’s a pretty simple script, once you work out what it needs to do.

How X does keys

Your keyboard connects up through a kernel device driver — almost certainly, the USB or “AT” (as in, the IBM PC/AT that introduced the round DIN keyboard socket) interface. This gets translated into a character device special file that programs (eg, X) can read from; perhaps something like /dev/input/event6.

X connects this character device special file to its XInput layer as one input device, and gets from it scancodes — more-or-less, these are codes that mean something like “the fourth key on the second row,” but don’t carry any symbolic meaning. XKB then translates these into keyboard symbols, like “x” or “b” or “Right Shift” or “Control + System Request.” (If you use a more complex writing-system, another level of translation might be in play, as well; perhaps converting Pin1Yin1 sequences into Han characters, or stacking Jamo into syllable blocks … but, you already knew about that, if you speak Chinese, Japanese, or Korean.)

Normally, Gnome sets XKB to use the same mapping for all connected keyboards. We’re going to break that.

In my case, I use a highly customized modified USB Dvorak keyboard, but I want to leave the internal keyboard in my laptop and the PS/2-connected alternate keyboard on my desktop machine as “normal” US Qwerty layouts.

Gathering the pieces together

First, you need to know the X keymap that you want as your base. Go through the Settings panel Region & Language → Input Sources to set it up as you would normally; then, extract its internal code name with (from a Terminal) — gsettings get org.gnome.desktop.input-sources sources — you’ll see a result like [(‘xkb’, ‘us’)] — the code you want here is ‘us’. Repeat for your other keyboard’s map (my other keyboard is type spacey, which you’ll see below).

Then, let’s identify your keyboards’ ID’s at the XInput level — this is where the physical keys’ signals are coming in, before XKB assigns them to key symbols. Just run xinput (again, from a terminal) and you’ll see something with a “Virtual core keyboard” and a set of “slave keyboards” under it. If you have a keyboard on a PS/2 or AT connector, you’ll probably see something like “AT Translated Set 2 keyboard;” USB keyboards are just, “USB Keyboard.” (You’ll probably also see video devices, laptop hot-keys, or other “keyboard-like” devices listed, which you can totally ignore for this purpose.)

To clarify which keyboard is which, you might use xinput list-props nn to see the details of a particular device. EG: if you have two USB keyboards, one of which is 9 and the other is 13, xinput list-props 9 might show that one of them has Device Node (270): “/dev/input/event8” … and find /sys/devices -name event8 might give you a beautiful string like /sys/devices/pci0000:00/0000:00:14.0/usb1/1-13/1-13.2/1-13.2:1.0/0003:04D9:0169.000B/input/input28/event8 (OK, maybe it’s not so beautiful.) The “nice” thing about that is that you can lsusb to find the brand name of your keyboard and match it up to the numbers in the middle of that sequence — eg. “Bus 001 Device 085: ID 04d9:0169 Holtek Semiconductor, Inc.” If you have two keyboards with the same model, you could have a problem here …

Building the script

So, on to the script. There are three steps we’ll need to perform:

  1. Set the default key map for all devices;
  2. Locate the keyboard XInput device ID(s) of the one(s) that will be different;
  3. Change only its (their) keymap(s).

The second step, unsurprisingly, is the “hard part.”

The script, with step 2 skipped, looks something like

#!/bin/bash
setxkbmap 'us'
for device in $(TODO MAGIC)
do
   setxkbmap -device $device 'spacey'
done

So … what goes into TODO MAGIC … ?

If your keyboards are visibly distinct in the xinput list, you could do something like:

⇒ xinput -list | grep ‘USB Keyboard’

… to locate the one you want. This will give you a small list, like:

↳ USB Keyboard id=12 [slave keyboard (3)]
↳ USB Keyboard id=13 [slave keyboard (3)]

(Note that these are both the same physical keyboard, in my case.)

If that’s what you wanted, you can trim the results with

… | cut -d= -f2 | cut -f1

which, all together, gives us

⇒ xinput -list | grep ‘USB Keyboard’ | cut -d= -f2 | cut -f 1
12
13

… Just what we wanted for the for loop.

#!/bin/sh
setxkbmap us
for device in $(xinput -list | grep 'USB Keyboard' | cut -d= -f2 | cut -f 1)
do
 setxkbmap -device $device spacey
done

The above is more-or-less identical to what I use.

Multiple USB keyboards?

If you need to do more work to narrow down the device, you might have to wrangle the USB vendor/product ID’s into play.

usbid=04D9:0169
for device in $( xinput … )
do
    dev=$(xinput list-props $device | grep 'Device Node' | cut -d: -f2)
    devpath=$(find /sys/devices -name $(basename $dev))
    case "$devpath" in
       *"$usbid"*)
          setxkbmap -device $device spacey
          ;;
    esac
done

This is using a relatively obscure shell feature: case “$devpath” in *”$usbid”*) … ;; esac is checking whether the usbid string exists within the (longer) devpath string. You could think of this as a way of asking, “if devpath contains the substring usbid.” (If you’re unfamiliar with Bourne shell, note that esac is case spelled backwards. In the same way, the end of an if block is fi. do, however, ends with done.)

Gnome Session

In order to make life a little more pleasant, I have also added a session script to run k whenever I log in.

In ~/.config/autostart/keyboard I have:

[Desktop Entry]
Version=1.0
Type=Application
Name=Set keyboard maps
GenericName=Set keyboard maps
Comment=Set keyboard maps
Icon=keyboard
Categories=System;
Exec=k
TryExec=k
Terminal=false
X-GNOME-Autostart-Delay=4

And, likewise, for GDM:

 ⇒ sudo su - gdm -s /bin/bash
-bash-4.3$ mkdir -p ~/.config/autostart
-bash-4.3$ cat >  ~/.config/autostart/keyboard.desktop
[Desktop Entry]
Version=1.0
Type=Application
Name=Set keyboard maps
GenericName=Set keyboard maps
Comment=Set keyboard maps
Icon=keyboard
Categories=System;
Exec=k
TryExec=k
Terminal=false
X-GNOME-Autostart-Delay=4
^D^D
-bash-4.3$ logout

I do still have to run this manually, eg, after switching users or the machine sleeping. Thus, the immensely short name “k,” so I’m not fumbling around trying to enter a long name on the wrong keymap.

PS.

My actual k script has these two lines to set key repeats properly, due to deficiencies in my spacey key map:

xset r 66 ; xset r 105

Maybe some day I’ll fix the keymaps, but, for now, this works for me.

Re-indent things sanely

Suppose you have, oh, a few jillion lines of code.

Now, suppose that this code was keyed in by cruel people, and its indentation is all kinds of messed-up.

Shocking, right?

Maybe half of it uses 10-column tabs, and half of it uses 3-space indents. Maybe it’s Lisp code written by folks who had no idea that there are rules about these things. Maybe big chunks of it were wrapped in “if… ” blocks and never indented to reflect that.

Step 1. Make sure your Emacs is set up to indent things the way you want.

Add this to your init.el and eval it:

(defun indent-buffer ()
  "Indent an entire buffer using the current syntax settings."
  (interactive)
  (save-excursion
   (global-trim)
   (goto-char (point-min))
   (while (re-search-forward "\t" nil t)
          (replace-match " " t t)))
  (indent-region (point-min) (point-max)))

This, you will notice, trims trailing whitespace, replaces every TAB with a space, and then re-indents the entire file.

Test by opening any one file, and type M-x indent-buffer RET.

OK, now you have one theoretically-legible file, right?

Step 2. Repeat for every other file.

But, we’re not going to do that manually, that would be masochism.

find . -name \*.c -exec emacsclient -e \
  '(with-current-buffer (find-file "{}") (indent-buffer))' \;

Repeat with each appropriate file-extension.

Step 3. Save!

The emacsclient invocation above intentionally doesn’t save any files. Hit C-x b and you’ll see all the dirty buffers it just changed. C-x s to save-some-buffers … and if you’re confident they’re all good enough, hit ! to “yes to all” it.

Step 4. Double-check with git

Now, you’re doing this on source, so you surely have it under version control, right? And before mass-re-indenting the whole codebase, you had a clean checkout, right?

git diff -w should show you no changes, because all that changed was whitespace.

So you can git commit -am ‘Re-indented’ without shame.

Unless it was Python code. If it was Python, you’re just screwed.

How to take a screenshot on “almost any” computer

As of May, 2017 (*updated), here are the most reliable instructions to take a screenshot of a running program on your computer, with the built-in tools of its system software.

Continue reading