Information gathered from reddit and saved here to keep it open https://www.reddit.com/r/pinball/comments/1mxozc2/pinball_2000_development_lore_part_11/ INITAL: I worked at Williams, as a programmer, mostly on Pinball 2000. If there are sufficient people who would like to hear some of the inside folklore of developing the system and working on the games, I'd enjoy sharing some of that and/or asking people's questions. It was an intense period in my life, full of emotions, and I expect there are things only I know and also things only I remember. Mods, if this is out of line or there are specific ways to handle this, let me know and we can figure out an appropriate format This was long, long before I came out to myself, so you won't find anyone called Coral on any playfield. Please don't out me, it's not a secret but it is a rude thing to do to anyone! I figure this community will be kind, which is partly why I'm offering to share stories from the dinosaur days PART1: These are my experiences as part of the Pinball 2000 team. Feel free to ask questions. I'll gather up multiple answers into one comment like I did with the initial post. Now, without further ado… Part 1 - Background, seeing the first prototype and joining the programming team In early 1998 I was working on making a WPC version of Big Bang Bar. I had a Capcom game in my office as a reference, and next to it I had a WPC cabinet with a whitewood made from Capcom playfield parts. I had almost the whole ruleset working, but there was no animation or sound at all. I had jumped at the chance to work on this because I liked the game, I hadn't had a chance to be in charge of a game's programming, and I agreed that we could make this game quickly and have it be successful. I was worried because whenever I asked when we'd get the assets licensed from Capcom I got non-answers, but I was really enjoying doing all the things you needed to program a full WPC game. It was common knowledge that pinball was not doing well as a business, and Neil Nicastro the CEO was not known for his sentimentality. Everyone was head-down on their various projects although I don't remember exactly what everyone was working on specifically. I knew JPop (John Popadiuk's nickname) was working on a pinball game with a CRT monitor in the backbox instead of the dot matrix display and backglass. He had a couple of programmers and an artist involved. I'd seen it a little bit and they had some simple gameplay. I thought it was interesting but I wasn't especially spurred to new ideas by it. One day I got invited to see something that wasn't upstairs in pinball engineering. I think it was across the street in the Midway 2727 building but I may be misremembering. Several of us trekked over and into the room. I forget who else I was with but I think Louis and maybe Dwight. There were two cabinets. One was Formula 1 themed with an angled backbox that was partly a mirror. Apparently this was Python's idea. I never saw it again and I didn't understand what it was even supposed to be demonstrating. In any case, what we were really there to see was Pat and George's demo of their holo-pin concept. It was super, super cool even with just the static images of the mech displayed by George's Amiga. My brain lit up with ideas. I really can't overstate how strong an impression this made on me. I instantly knew that I wanted to work on this! Everyone seeing this demo for the first time was similarly excited. It was just electric. This felt revolutionary, a unique moment that the world would never be the same after. When I got back to my office I immediately started thinking of ways to do Big Bang Bar as a holo-pin. I started a text file and poured my thoughts into it. I'll talk about those thoughts in a later post, but the important point is that I instinctively knew that nothing more was going to happen with the WPC version. Now, part of the reason I'd even been working on Big Bang Bar in the first place was because the other programmers were sceptical about it. I was also a "problem child" who'd not done myself many favours and so people were just fine having me out of their way. That's important context because later that afternoon Tom came into my office to tell me I'd be working with him on this new thing and, as he bluntly put it there was to be "no fucking around". I promised him I'd do good work, that I understood his concern and I wanted to earn his trust. With that, my time on what was to become Pinball 2000 had officially begun. I don't remember if I had one of the JPop-style cabinets first, or just a monitor and CPU board. There would've been some setup but you really didn't need that much on your Windows machine. Cygwin to run the compiler, linker etc, the RCS client (source code version control), a TFTP server you just ran in the background, and a serial cable. The CPU board had Ethernet and an ISA card to boot it. It would connect via TFTP and download whatever you'd just built. There was a button wired up to the reset pin on the CPU so you just hit the button when the thing crashed or you had new code to try. It could already scan switches and fire coils in order to support the gameplay prototypes JPop's team were doing. We had circuit boards with a big grid of toggle switches for programmers who didn't have or need an actual playfield, so I would've plugged one of those into it. I didn't need anything else. This is how new projects usually start out. You get things hooked up, you get the source code, you build it and you run it. Once that's sorted out you can start to work. Reading code, making changes, talking to teammates about what was most important. My first tasks were all about graphics, and I'll discuss that stuff in part 2. (As an aside, we'd made WPC setups like this in the past. I'd had one on my desk, just a backbox with a power supply bolted to its top. You could plug it into a playfield, a test fixture of some kind, or one of those switch boards. That backbox was where one evening I'd had my first experience with the WPC-95 sound board crashing, which made it blare out a horrible sound VERY LOUDLY INDEED for several seconds. It went off right by my head and I was a bit discombobulated when Larry came to check on me. I think it happened at least once to pretty much every programmer) Part 2 - Early decisions on how to handle graphics and the display This part will be quite technical because I'll discuss some hardware capabilities and trade-offs in detail. I'll try to keep it from getting too esoteric. The code already had limited support for graphics. Part of the 8MB of RAM was set aside to hold a video framebuffer. It could output the framebuffer to a monitor, and it could copy sprite data from ROM into RAM, including printing text letter by letter. I don't remember if there was any data compression already. There was also a port of a graphics library called Allegro, which was freely available source code. Given the timing I think we would've been using version 2.1 or 2.2 but I'm not sure. That library had all the features the prototype needed but it would not meet all our needs. I started with a few basic assumptions: The display would be a shared space Graphical effects shouldn't have to know about what else was being displayed We would have to work with a "low-res" monitor ROM space would be limited and precious These assumptions drove every choice I made in the beginning. I'm sure I discussed them with other programmers but I don't remember in what order and with whom. Tom must've had input for 3 and 4 because I didn't know exactly what the hardware could do, how big the ROMs could be, or what the constraints for video output were. It helped that I had written "graphics demos" in ARM assembly language for the computer I'd owned in Britain so I was familiar with things like sprites, masks, palettes, resolutions and so on. Incidentally the CPU inside basically every smartphone on the planet is derived from the CPU inside that computer, albeit distantly these days. Steve Furber and Sophie Wilson designed the Acorn RISC Machine CPU. That CPU was used in the Acorn Archimedes line of computers including the A3000 I'd owned. Nowadays ARM stands for Advanced RISC Machine and the instruction set is 64 bits vs the original 32 bits but without the work of those two, the world of computing would be very different. The display was set up for 256 colours, so 8 bits per pixel, with a colour palette of 256 entries. That meant you could have up to 256 unique colours on the screen at any time and only needed 1 byte per pixel so it was fairly fast to draw. The downside to this was that if you changed what any one palette entry looked like all the pixels that used that entry would change colour. This means you either have to divide the palette into groups (say, 8 groups of 32 entries each) and limit effects to one per group so they can change their entries without clashing, or pre-allocate a few palettes that the effects can use together. I decided not to do these things. I wanted something easier and was prepared to have lower overall performance, so I changed the setup to use 16 bits per pixel where each pixel stored its own colour value. No palette clashing! However, as in all things, there were downsides. First, we'd be using twice as much memory for the display and taking twice as much time to draw into that memory. Since the big differentiating thing for Pinball 2000 was the video display I was concerned about that. Second, we wouldn't have quite as much control over the colours. With the palette entries you could set 256 levels independently for red, green and blue. With 16 bit colour you could only get 32 levels each (actually 15 bit RGB555 colour; 16 bit RGB565 would let you have 32 for red and blue and 64 for green but I chose not to do that for reasons we'll get into later). Since players wouldn't be looking at the display directly and there'd be so much ambient light I decided that wasn't going to matter. We also needed to choose a screen resolution. The prototype was set up for 640x240 pixels and there was a reason for that. In the arcade industry what we called a "low-resolution" monitor meant that you could only have so many rows of pixels. CRT monitors use electromagnets to paint the screen with electrons. The monitor is driven at 60 frames per second, so if you have 240 rows that means you're changing the strength of the vertical electromagnet 14,400 times a second. Low-res monitors can only handle up to around 15kHz for that. You need a bit of extra time because when you reach the bottom of one frame you have to move the beam back to the top for the next frame. Higher-res monitor could change more quickly so they could display more rows. There's a similar constraint for how many columns of pixels (basically how fast can you move the electron beam along a single row), but all I remember is that 640 pixels wide was fine. Since the monitor aspect ratio was 4:3, 640x240 meant pixels would be twice as high as wide (1/160th of the width, 1/80th of the height) so I thought about dropping to 320 so the artists could work with square pixels and we'd only have to draw half as many each frame. I probably talked about it with Tom a little but I don't think it was ever more than a vague idea. I certainly don't remember testing it out or showing the difference to other people. This wasn't the end of the decision making process though. Not only would we be using twice as much RAM for the display, but 16-bit art would take up more ROM space. We only had 64MB for ROM and 4MB of that had to hold an early version of the game code so you could boot the game directly from it. Sounds were handled differently, so they didn't have to fit there, but 60MB for all the artwork in the game was not very much. We'd need image compression to make this feasible and that would add complexity because our image processing tools would need to do the compression, and we'd have to add decompression to the system. It did have a benefit beyond just fitting more art into the game. Reading from ROM was slower than reading from RAM. So the smaller the data in ROM, the less performance hit there'd be copying and decompressing it. This mostly covered my four key assumptions. Compression would come later (I'll talk about it in part 3). We were fine using a low-res monitor. Basic performance was acceptable and we didn't have to deal with palettes or clashing. There was still an important piece missing, however. How were different rules going to share the display easily? It occurred to me that windows in a GUI were like that. Different apps could overlap their windows, and things were drawn in a consistent order. On Unix there was a program called a "window manager" that organised all that, so I could make my own equivalent! I called it the DisplayManager and the individual things were Displayables. Game code could create a Displayable, register it with the DisplayManager and it would get drawn over and over, every frame, until it was unregistered. When a Displayable was registered it was given a Z value and the list of Displayables would be drawn in increasing Z order so things wouldn't flicker under and over each other. At the beginning of each frame the display needed to be cleared. By default it would just be wiped to black but I made this overridable in case a game wanted to do something special - maybe they were always showing some static piece of art so they could copy it directly over the old pixels and save time. Similarly, Displayables needed to know how to draw themselves. I started with two kinds. One was created with a specific width and height and would allocate that much memory. The game code could update that memory and the Displayable would copy it onto the display when the DisplayManager told it to. The other was "self-draw". Instead of allocating any memory it would just have a function that got called at the right time. This was so things that didn't need to pre-allocate memory were easy to create. A starfield could self-draw and just update the relevant pixels. Something that wanted to process things already drawn on the display (say to tint or magnify them or something else) could read those pixels, modify them and write them back. Basic shapes like lines or rectangles or circles could be drawn directly onto the display. We didn't use this very much, but it was easy to implement and it was helpful on several occasions. I got all this working pretty quickly. At that point I was coming to work really early on Monday (maybe 4am) to give me solo, quiet time for things like this. When colleagues were around I could talk to them about needs and wishes and so on, but it was hard not to get distracted. I made a demo of coloured ellipses to show how they could overlap and be moved around and shown and hidden. I was confident that my assumptions were right and that this would be flexible, easy to use and help us make games that looked great. hese are my experiences as part of the Pinball 2000 team. Feel free to ask questions. I'll gather up multiple answers into one comment like I did with the initial post. Now, without further ado… Part 2 - Early decisions on how to handle graphics and the display This part will be quite technical because I'll discuss some hardware capabilities and trade-offs in detail. I'll try to keep it from getting too esoteric. The code already had limited support for graphics. Part of the 8MB of RAM was set aside to hold a video framebuffer. It could output the framebuffer to a monitor, and it could copy sprite data from ROM into RAM, including printing text letter by letter. I don't remember if there was any data compression already. There was also a port of a graphics library called Allegro, which was freely available source code. Given the timing I think we would've been using version 2.1 or 2.2 but I'm not sure. That library had all the features the prototype needed but it would not meet all our needs. I started with a few basic assumptions: The display would be a shared space Graphical effects shouldn't have to know about what else was being displayed We would have to work with a "low-res" monitor ROM space would be limited and precious These assumptions drove every choice I made in the beginning. I'm sure I discussed them with other programmers but I don't remember in what order and with whom. Tom must've had input for 3 and 4 because I didn't know exactly what the hardware could do, how big the ROMs could be, or what the constraints for video output were. It helped that I had written "graphics demos" in ARM assembly language for the computer I'd owned in Britain so I was familiar with things like sprites, masks, palettes, resolutions and so on. Incidentally the CPU inside basically every smartphone on the planet is derived from the CPU inside that computer, albeit distantly these days. Steve Furber and Sophie Wilson designed the Acorn RISC Machine CPU. That CPU was used in the Acorn Archimedes line of computers including the A3000 I'd owned. Nowadays ARM stands for Advanced RISC Machine and the instruction set is 64 bits vs the original 32 bits but without the work of those two, the world of computing would be very different. The display was set up for 256 colours, so 8 bits per pixel, with a colour palette of 256 entries. That meant you could have up to 256 unique colours on the screen at any time and only needed 1 byte per pixel so it was fairly fast to draw. The downside to this was that if you changed what any one palette entry looked like all the pixels that used that entry would change colour. This means you either have to divide the palette into groups (say, 8 groups of 32 entries each) and limit effects to one per group so they can change their entries without clashing, or pre-allocate a few palettes that the effects can use together. I decided not to do these things. I wanted something easier and was prepared to have lower overall performance, so I changed the setup to use 16 bits per pixel where each pixel stored its own colour value. No palette clashing! However, as in all things, there were downsides. First, we'd be using twice as much memory for the display and taking twice as much time to draw into that memory. Since the big differentiating thing for Pinball 2000 was the video display I was concerned about that. Second, we wouldn't have quite as much control over the colours. With the palette entries you could set 256 levels independently for red, green and blue. With 16 bit colour you could only get 32 levels each (actually 15 bit RGB555 colour; 16 bit RGB565 would let you have 32 for red and blue and 64 for green but I chose not to do that for reasons we'll get into later). Since players wouldn't be looking at the display directly and there'd be so much ambient light I decided that wasn't going to matter. We also needed to choose a screen resolution. The prototype was set up for 640x240 pixels and there was a reason for that. In the arcade industry what we called a "low-resolution" monitor meant that you could only have so many rows of pixels. CRT monitors use electromagnets to paint the screen with electrons. The monitor is driven at 60 frames per second, so if you have 240 rows that means you're changing the strength of the vertical electromagnet 14,400 times a second. Low-res monitors can only handle up to around 15kHz for that. You need a bit of extra time because when you reach the bottom of one frame you have to move the beam back to the top for the next frame. Higher-res monitor could change more quickly so they could display more rows. There's a similar constraint for how many columns of pixels (basically how fast can you move the electron beam along a single row), but all I remember is that 640 pixels wide was fine. Since the monitor aspect ratio was 4:3, 640x240 meant pixels would be twice as high as wide (1/160th of the width, 1/80th of the height) so I thought about dropping to 320 so the artists could work with square pixels and we'd only have to draw half as many each frame. I probably talked about it with Tom a little but I don't think it was ever more than a vague idea. I certainly don't remember testing it out or showing the difference to other people. This wasn't the end of the decision making process though. Not only would we be using twice as much RAM for the display, but 16-bit art would take up more ROM space. We only had 64MB for ROM and 4MB of that had to hold an early version of the game code so you could boot the game directly from it. Sounds were handled differently, so they didn't have to fit there, but 60MB for all the artwork in the game was not very much. We'd need image compression to make this feasible and that would add complexity because our image processing tools would need to do the compression, and we'd have to add decompression to the system. It did have a benefit beyond just fitting more art into the game. Reading from ROM was slower than reading from RAM. So the smaller the data in ROM, the less performance hit there'd be copying and decompressing it. This mostly covered my four key assumptions. Compression would come later (I'll talk about it in part 3). We were fine using a low-res monitor. Basic performance was acceptable and we didn't have to deal with palettes or clashing. There was still an important piece missing, however. How were different rules going to share the display easily? It occurred to me that windows in a GUI were like that. Different apps could overlap their windows, and things were drawn in a consistent order. On Unix there was a program called a "window manager" that organised all that, so I could make my own equivalent! I called it the DisplayManager and the individual things were Displayables. Game code could create a Displayable, register it with the DisplayManager and it would get drawn over and over, every frame, until it was unregistered. When a Displayable was registered it was given a Z value and the list of Displayables would be drawn in increasing Z order so things wouldn't flicker under and over each other. At the beginning of each frame the display needed to be cleared. By default it would just be wiped to black but I made this overridable in case a game wanted to do something special - maybe they were always showing some static piece of art so they could copy it directly over the old pixels and save time. Similarly, Displayables needed to know how to draw themselves. I started with two kinds. One was created with a specific width and height and would allocate that much memory. The game code could update that memory and the Displayable would copy it onto the display when the DisplayManager told it to. The other was "self-draw". Instead of allocating any memory it would just have a function that got called at the right time. This was so things that didn't need to pre-allocate memory were easy to create. A starfield could self-draw and just update the relevant pixels. Something that wanted to process things already drawn on the display (say to tint or magnify them or something else) could read those pixels, modify them and write them back. Basic shapes like lines or rectangles or circles could be drawn directly onto the display. We didn't use this very much, but it was easy to implement and it was helpful on several occasions. I got all this working pretty quickly. At that point I was coming to work really early on Monday (maybe 4am) to give me solo, quiet time for things like this. When colleagues were around I could talk to them about needs and wishes and so on, but it was hard not to get distracted. I made a demo of coloured ellipses to show how they could overlap and be moved around and shown and hidden. I was confident that my assumptions were right and that this would be flexible, easy to use and help us make games that looked great. Part 3 - Satisfying artists while still making smart compromises Pinball machines are creative works, made by a team with different specialties. Some roles are more technical and some are more artistic, but it's good for team members to have mutual understanding and mutual respect. Even though I wasn't on a game team I felt it was very important to get to know the artists especially since most of them were new. We had Adam and Scott, both of whom had made dot matrix art for WPC, so that was where I started. 15 bit colour (as described in part 2) was very helpful for their work, so that was good. We needed a way for the art to have a pixel be transparent and there were two approaches. We could've used a mask (whether the unused bit, or a separate image entirely) or we could use one specific colour as a 'key colour'. Pixels of that one colour are treated as transparent when drawing the image. I don't remember who drove this conversation, but it was easy for us to choose that second option and to use pure magenta (so 31 red, 0 green, 31 blue) as the key colour, because that's such a harsh colour and the artists didn't think they'd use it much anyway. They also knew that even if they did want to use it, they could use an almost-identical colour (e.g. 31 red, 1 green, 31 blue) and it would look fine. The advantage for me of using a key colour is all the existing software tools would work as-is and it would be easy for programmers or artists to understand what happened. If we had used the 16th bit you'd have an opaque and a transparent version of every colour value and it would've been hard to visually tell what was going on with the source art when things looked wrong on the game screen. If we'd made a separate image for the mask that would've made things harder for the artists because they'd have to update the art itself and its mask together. We'd also have two chunks of data in ROM that needed to be combined in RAM in order to update the display. Modern video hardware works so differently that these aren't meaningful concerns any more, but they really mattered in 1998! I think it was Adam who really wanted alpha-blending, which the video hardware didn't support natively. I could've done this purely in software, but that would've been very slow. I had to explain the basics of why and I also offered a compromise, which was that you could stipple transparent pixels with opaque ones by making alternate pixels magenta. Think of white squares vs black squares on a chessboard. It's not great, but it's better than nothing. Alpha blending is a sort of translucency. Rather than having a pixel be opaque or transparent, it lets you combine the pixel you're drawing with whatever pixel is already in place underneath it, sort of how sunglasses stop some of the light coming through but not all of it. For example, blending pure blue and pure green at 50% alpha will give you a medium cyan tone like teal. To do this you need to multiply one pixel by the alpha, the other pixel by 100% minus the alpha, and add the results together. So pure blue becomes 50% blue, pure green becomes 50% green and when you add the two together you get 50% cyan. You have to do this separately for each colour channel. That works out to 6 multiplies, 6 divides and 3 additions as well as the work to separate and recombine the colours. The CPU we were using was not optimised for this sort of math, so it would've taken probably 20 times longer per pixel, plus the alpha values would've had to be stored separately. I sympathised with the artists a lot, but I wasn't willing to do this work. Artists are passionate about making everything as beautiful as possible, so they would've used it in all their art and the performance would've been really slow. It's unfair to expect artists to limit themselves to satisfy unintuitive, highly technical constraints when they could have a clear rule. If we'd upgraded to video hardware that could do this natively, I would've made it first on my list of updates. Since the artists had been part of the decision making process and I could show I was considering their needs, the lack of alpha blending didn't become a contentious issue. This really helped because the next compromise would be a really, really big one. This was about image compression. There are lots of ways to compress images so they take less storage space. There's no single optimal technique because there are always trade-offs. I knew we'd need something that was efficient for storage and fast to decompress. Compression could be slow because it was done offline and only needed to happen once, but decompression would happen whenever we wanted to have the image in RAM. I was worried about this and I'm sure Tom and I would've talked about it but I didn't have a clear solution. We were lucky because one of the programmers working on console videogames in the San Diego office, Mark, was a big pinball fan and he showed us a really good way to solve our problem. He'd had very similar requirements for making a console port of Mortal Kombat so he could fit the huge quantities of animation into a game cartridge. The compression involved finding repeated pairs of pixels in an image and building a dictionary of the most common colour pairs. Then, instead of listing each pixel individually, it could say to repeat a dictionary entry (so a specific pair of colours) however many times; this is a version of run length encoding (RLE). This was easy to add to the image processing tools, and the decompression code was fast. However, in order to be effective it needed the source image to use a limited number of individual colours so there'd be plenty of instances of a smaller number of colour pairs. Mark had made two versions of this, one that allowed 64 unique colours and a 64 entry dictionary, and another that only allowed 32 colours but had a 128 entry dictionary. The latter version was great for things like icons and fonts where they'd only use a few colours anyway. The artists were very unhappy with this idea whenever I talked it over with them. I'd given them the ability to make lovely art with colour gradients and subtle shading and now I wanted them to limit that by making each image only have a fraction of all those possible colours! We talked it over repeatedly, including Tom getting involved, but there wasn't an agreement between us all. The thing that settled the matter was that when Mark came to Chicago I asked him to talk to the artists directly without me or other pinball programmers present. I don't know what he said to them, but he convinced them that this was a good solution and they'd still get to make beautiful things and the games could have lots of nice art stored in the 60MB of ROM. If I hadn't worked to gain the artists' trust in the beginning I'm not sure even he could've convinced them. By the way, Mark has long worked for Stern Pinball (and is the most senior programmer in the company, if I understand his job title correctly - if not I expect he'll appear to set the record straight). It's important to make smart technical decisions, but it's also important to foster mutual respect. A tight-knit team with fewer resources will usually do a much better job than a fractious team with plenty of powerful features. This way of thinking came up over and over for Pinball 2000 whether just among programmers, or designers, or engineers or multiple types of colleagues. We all knew it was do or die for pinball at Williams and we all wanted to succeed and that helped us coalesce around a single vision. Part 4 - How we hashed out technical decisions and competing philosophies NB: I had a different title for this section originally but I decided it would be more interesting to narrow it down and expand one of the later parts. Any collaborative creative project will have a variety of viewpoints and personalities amongst its members and Pinball 2000 was no exception. Tom was the master of deadpan snark. Duncan was calm. I was emotionally reactive and volatile. George inspired passion. JPop appeared whimsical but was actually a very deep thinker. These were the people I worked most with in the early days, but it's just as true for everyone else who brought Pinball 2000 to life. We all had the same goal, but we had to trust each other a great deal. Sometimes that brought friction. It was especially hard for me because I was not used to working closely with others, and my way of thinking is often quite different from other people. Luckily we all got used to each other's quirks very quickly. Some of the times I remember most clearly from the early days of the project were when Tom and I would be architecting something and being really tough on each other's ideas. We never got angry at each other, but there were no sacred cows when it came to programming. I loved those times because I could be confident in the quality of my solutions if Tom was happy with them, or I'd learn something (or at least learn what I needed to learn more about) if Tom found flaws in my designs. One example of this is to do with memory management. Any program that asks the OS to allocate memory to it also needs to return that memory to the OS when it doesn't need it any more. If it keeps allocating memory and not freeing it eventually the memory will run out and the program will crash. That's called a memory leak. Tom was adamant that we should not let this happen and I agreed with him. Having to reboot a pinball machine is silly. In fact, having to reboot any device that should just stay powered on and doing its thing for weeks at a time is silly, but that's a rant for another time and place. His solution was to track which thread (basically which task in the system) had allocated the memory and if that thread exited or was killed, all the memory still allocated to it would automatically be freed. If a thread itself spawned another thread, that memory was considered allocated by the parent thread. Since almost all threads were killed when the ball drained or when the game ended this was a really good way to avoid memory leaks. My problem was that the display code needed to manage its own memory both for individual Displayables but also for its internal state. I wanted a thread to be able to start up some graphical effect and not have to keep track of it and especially not to have to worry about corrupting memory used elsewhere. We got together in an empty office and talked for a good while. Typical programmer stuff, drawings on whiteboards, back and forth. We came up with a solution that let a thread sever itself from its parent. I don't remember the details but it was a concise synthesis of several things we had explored For WPC games the multithreading was co-operative. Until you exited or slept, nothing else would run. That made most things easy to think about but it had drawbacks. Pinball 2000 had a much more powerful CPU, and its system software was based on a tiny Unix-like OS kernel called PC-Xinu (an acronym - Xinu Is Not Unix - and we called our version Xina - Xina Is Not Apple - referring to the WPC system software. Recursive acronyms are an example of humour in older programmers). That meant pre-emptive multithreading was the default. Tom was extremely knowledgeable about that kind of programming, but I hadn't done much of it. I had a learning curve to climb as I worked on my parts of the codebase so I didn't cause deadlocks or corrupt data by accessing it from multiple threads without protection. I wasn't the only one who would have to learn about these dangers. On WPC individual threads were low overhead, their thread IDs were pre-assigned and you could check if a thread with a particular ID was active. A hurry-up rule could spawn a thread with that known thread ID and the thread would simply decrement a counter and sleep, until the counter reached zero. Whatever code ran when you shot a ramp, for example, could check if the thread was alive. If it was, it would call whatever code handled the hurry-up being collected and that code could kill off the timer thread. There was no need for some other flag or variable to hold the state of the rule. Tom felt it was important to replicate this paradigm in Pinball 2000 and made an equivalent framework for "Apple-like" threads. I didn't need to care about any of that for my work, but there was definitely a lengthy discussion about whether it was ok for these particular threads to be pre-emptive, or co-operative at least among each other. The reason I bring this up is that it illustrates something that elevates things from good to great. Everyone on the programming team at Williams was super talented, but we all had strengths and weaknesses. For example, in my opinion and this is only my opinion, the most technically proficient programmers were Lyman, Tom and Duncan and the most creatively proficient were Lyman, Dwight and Keith. Lyman was unique in that he could do it all (I learned more from working with him than anyone else. At his remembrance someone called him "the Clint Eastwood of pinball" and I think that's a good analogy. I miss him). That diversity of skills was important and it's why Williams was able to make such good games. We needed our code to be usable by all of the programmers whatever their biggest strength or weakness was. A good piece of code is efficient and flexible and well-designed, but it can require a lot of skill to use well. A great piece of code is all these things except that you don't need as much skill. It's intuitive and straightforward and when you make something that uses that code it's less likely to have bugs. The WPC way was great. The Pinball 2000 way was good. As more game code got written the skill floor for people who'd previously worked with WPC became more apparent. One day this came to a head. I wasn't present for the discussion but I clearly remember Tom trenchantly saying "I'm making all the Apple-like processes co-operative" and at that point we moved closer to great. There were other cases of this involving my own systems but I don't remember the details, otherwise I'd use one. Please don't ever think I'm disparaging any of my colleagues. Part 5 - Higher-level support for graphical "display effects" akin to the WPC way of thinking There was now a way to use the display as a shared space, but we still needed to convey information and choreograph between multiple users of the display. As well as individual Displayables we needed to group them and hide or show them together. The WPC games had a concept of a "display effect" or "deff". When nothing else needed to use the dot matrix display it would show the score. Something more important, for example locking a ball, could override the score sweep. That deff would play its animation, show a message about the ball being locked and then exit. One deff could pre-empt another. Earning a replay or an extra ball would cancel a less important deff, such as increasing the bonus multiplier. Those were "foreground deffs". If they were interrupted they would not be restarted. There were also "background deffs" which could be paused by a more important deff and would resume when there was nothing pre-empting them. For example, when you locked a third ball you would get a foreground deff to show multiball was starting. Then a background deff would take over from the default score sweep so it could share details like what to do to score a jackpot. If you shot a jackpot a foreground deff would play and then the multiball background deff would resume. Once you drained back down to one ball, a foreground deff would summarise the multiball. The multiball background deff would finish and the score sweep would resume. The game could have multiple background deffs stacked by priority. For example if a hurryup was active when you started multiball and was still going when you drained out of multiball (maybe the hurryup paused until then), the hurryup background deff would resume until the hurryup ended, and so on. The score sweep was the lowest priority and made sure the display was always being used. I knew Pinball 2000 would need a way to do the same things. The jet bumpers might show animations every time the ball hit them and we wouldn't want stray Displayables to be accidentally left on the screen. We also had to support multiple foreground and background deffs being active at once. The dot matrix display could really only support one rule at a time, but our video display was shared by multiple rules. That made the choreography a bit more complicated, but it was not that different from how WPC games did things. We could keep a prioritised stack of deffs, some of which could be paused and resumed. Like there were Displayable items and a DisplayManager drawing them in order each frame, I built the equivalent things for handling effects. There was a DeffManager to control all the active display effects. A rule could ask the DeffManager to start a DisplayEffect and then not have to bother with it any further. When the DeffManager told a DisplayEffect to start, the effect would allocate a bunch of Displayables and register them with the DisplayManager. When the DeffManager told an active DisplayEffect to stop, the effect would unregister those Displayables and free their memory. When a DisplayEffect was pre-empted it could choose to be suspended or just let itself be stopped. When the DeffManager told a suspendable effect to suspend that effect would hide all its Displayables. When the effect was told to resume it would ask the DisplayManager to start showing its Displayables again. The Displayables still had their Z values so an explosion could draw over the top of a building owned by a different effect. If the explosion effect wasn't important it could be killed off without having to remove the building as well. DisplayEffects needed something like a Displayable's Z value. When a rule asked the DeffManager to start an effect it would give it a priority. Something important like earning an extra ball would have a high priority and something like the jet bumper DisplayEffect would have a low priority. This didn't fully solve the problem of what to pre-empt though, because something important that didn't need the entire display wouldn't want to kill off less important things that didn't interfere with it. I spent time thinking about this and chose to handle it by adding a threshold value that was given to the DeffManager along with the priority. The threshold meant "anything lower priority than this should be stopped or suspended". Suspendable effects would mostly have a threshold of zero. They didn't need to suppress each other for the most part. If multiple rules wanted to display something over a ramp, for example, the less-important effect could have a very low priority and the more-important effect would have a higher priority for itself, and a higher threshold than the other effect's priority. Whenever an effect started or stopped the DeffManager would go through its list of active effects and find the highest threshold. Any effect with a lower priority than that threshold would be stopped or suspended. Things that needed to commandeer the whole screen, such as multiball start, replay or extra ball would have a high priority and high threshold. Once that sort of effect finished and the threshold was recalculated, any suspended effects could be resumed if they were above the new threshold. All this complicated management was a black box and game programmers just had to set up their priorities and thresholds based on what they felt was most important for the player to see at any moment. Around the same time as I was building this system I added another convenience feature for Displayables. I made a new object, a Sprite, which was a Displayable that could be told how to scale or move itself, and/or to show successive image frames over time. The DisplayEffect could create a Sprite, set up its movement and animation and the Sprite would update itself automatically. Every time the DisplayManager started a new frame it would tell every Displayable to update itself. By default Displayables did nothing, but a Sprite would do what it had been set up to do. It could also bounce away or wrap around if it moved to the edge of the display. It could also be restricted to part of the display when behaving that way. It could restart its animation when it reached the end or play it back in reverse, ping-ponging back and forth. This was separate from being drawn so that hidden Displayables would automatically be up to date if they were made visible again later. We had very little time to make our first two games and it was very important to me that game programmers would have to spend as little time as possible making their graphics work. The more time they had to work on game rules and cool stuff the better. I was really pleased with the whole display management system. Part 6 - Miscellaneous silly anecdotes These are unconnected bits and they're not in any particular order. I either thought the situation was funny (sometimes only after the fact) or they show what life is like when you're involved in a project with so much passion and so much riding on the outcome. SNACKS! It was a lapsed tradition among the pinball programmers to go down to the lunch area in the afternoon, buy things from the vending machines and chit-chat just as a break from the grind. At some point in Pinball 2000 development we revived this, partly because someone left a hand bell up by our offices. Dwight would ring the bell and call out "Snacks! Snacks!" and we'd go. The bell was loud and obnoxious, but people tolerated the noise because most things were manic most of the time. I'd generally have a Diet Pepsi and a chocolate bar. I was averaging six bottles a day so my caffeine levels were high but not quite into heart palpitations territory. One day we were sat there talking and Tom looked over at me. He says "You're eating around the letters?!" and he was right. I often got one of those Nestle Crunch bars. I would leave the letters until last so I could eat them one at a time and rearrange them into anagrams. Crunch became churn but I forget how it went from there. PHONE TAG The company phone system wasn't sophisticated. If you called someone and they were already on a call you'd just get the busy signal. If you needed the person urgently you could call an extension and whatever you said would come out of speakers all over the building like an announcer at an event. You'd hear things like "John McCaffer, please call 123". People who were more important would get paged like this and you could gauge how busy they were by how many pages they got. Anyway, one evening I was in the bathroom and I heard someone get paged. Then someone else, presumably the person being paged, called in and paged the original person. The first person paged again with "... and please hang up your phone". The second person paged AGAIN with just "It's hung!". I didn't recognise the names and I don't think I ever met them. RESTAURANT CRITICS We had several places we went to eat on a regular basis, for lunch and for dinner. Some of them had nicknames. Sometimes the names registered a person's dislike of the place, but not always. For example there was a Popeye's nearby that people called "boneyards". Apparently one of the videogame teams ate there regularly and were in the habit of throwing chicken bones over their shoulders into the potted plants, which I neither witnessed nor would condone. There was a Mexican restaurant called 'Taco Y Salsa' that at one time had been a bar and Greg Freres had played a gig there when he was in a band. The staff had trouble with my British accent, but I liked the food. Larry came with us one lunchtime and was unimpressed. At some point after that we were deciding where to go and he called it "Tacos & Horsemeat". I think we stopped eating there not long afterwards. We used to get dinner at this diner called 'Golden Nugget'. I think there were several in the area, but I've no idea if they still exist. I would usually get either a burger or breakfast food. Keith always ordered french toast with a side of sausage. One time Lyman decided to join us, having been skeptical about the place beforehand. I thought their milkshakes were really good so Lyman ordered a chocolate shake. When it arrived the metal cup had a tiny piece of banana on it (I expect from a banana shake being made at the same time). Lyman was very unhappy with this and refused to ever go back to "Dog Nugget" as he subsequently named it. Bill got fed up with the usual selection of lunch places and pushed for us to try to somewhere new. It was called 'Nantucket Fish House' and it was close by. I know Nantucket is a real place but I have a dirty mind and so I kept thinking about what is usually rhymed with it in limericks. It was small and quiet and nondescript, but unfortunately the food was quite bad. I'm forgiving with most things but if you can't get fish & chips right when one of the words is in the name of your restaurant, you don't deserve repeat customers. We never went back and I think Bill went several months before resuming his quest to broaden our palates. THE TAPESTRY There was a Mexican restaurant down the block from where we worked called La Finca. The food was really good so it was a good place to take new people. There was also an ulterior motive, in the form of an initiation rite of sorts. There was a tapestry on the wall of a step pyramid, like the Aztecs built. One side was partly overgrown and the other was cleared of vegetation. We would ask new people to come up with an explanation why this might be the case, since the job involved creativity. It was fun to hear what people would come up with. Someone said it was because the blood from sacrifices ran down that side. My own answer had been that they were union workers so they were on a mandated break. Bill was hired before me so I wasn't present for this, but he told me his answer had been "It's a beach towel!" STEALTH I worked very late hours most days. I would arrive around 11:30am, do the things I needed to start the day and then go to lunch with the others. I would usually stay until 2am or even later. It was good to have time when I was on my own because I could avoid being distracted. I only lived five miles away so my evening commute was really easy. One night it was really foggy and there was almost no-one else on the road. I was tired and nearly home when someone on a bicycle came riding through the intersection towards me, on the wrong side of the road. He was a black guy with no lights on his bike, wearing dark clothing. I think the bike was dark grey or black as well. I don't think he could have been less visible than he was. It was lucky for both of us that I saw him at all. REMODELING As we got closer to putting the first game into production the factory got involved. They needed one of their engineers to help make sure the games could be built easily. There were often mechanical things that needed to be tweaked. One afternoon I came back from a trip to the vending machine (I drank a LOT of Diet Pepsi) and noticed a new hole in the drywall outside the office of one of the mechanical engineers. The thing is, this hole was at head height. It turned out that the manufacturing engineer had unilaterally decided that the slide rails under the playfield were unnecessary and didn't want to do anything with them. One of our people had been angry at this and punched a hole in the wall beside this person's head. The slide rails were added back to the production process. This was not the only time tempers flared strongly enough to lead to damage. The building manager tolerated a certain amount of destruction, but would make sure people knew when they were over the line. He'd worked for the company since before I was born and was a good guy. He dealt with a lot of bullshit from over-indulged creative people. He had two workers who would fix damage like this along with making layout changes. One was short and plump and the other was taller and thinner. We nicknamed them the Super Mario Brothers. They would be tasked to reconfigure things all the time. There was an open area with a bunch of chairs and they had to put walls around it. I don't know who wanted that and none of us pinball people thought it was helpful. I had no problem with them. They were just doing what they were told, but it was sometimes strange to find a door where there hadn't been one or a corridor that had been extended. EXPLETIVES I liked my office to be as dark as possible so that the only light game from my PC monitor or the game. I kept the lights off and my door ajar. At one point I had a board with a bunch of flashlamps laid out in two rows, with covers in all different colours. I wrote a little bit of code that would flash them randomly and put them inside my game so that it was like having a mini rave in my office. It must've looked odd to people passing my door. The lady who had the office next to mine worked in the drawing office keeping track of blueprints and so on. Her name was Nina and people called her the "purple dragon lady" because she loved purple clothes and didn't indulge people's foolishness. I had my little rave running one day and was really fired up working on something. When my code crashed my game I said, loudly, "Goddamn motherfucking piece of shit!". Nina immediately called out "Coral!" (actually my deadname, but I won't use that here) in that tone everyone knows as Mom Voice. I popped into her office and apologised, but she was smirking. She told me not to worry because she "had raised two boys". She was one of my favourite people so I did still watch my language a little more during normal work hours. ALL-NIGHTERS Some of us would work through the night and into a second day without going home to sleep. This usually only happened when we had a really important thing happening that second day, like a demo for the CEO. One night there were five or six of us and we got hungry, so we drove to the supermarket nearby. Picture a gaggle of slap-happy overtired programmers pushing a cart through the aisles and tossing random junk food into it. There were cookies, marshmallows and so on. I was in the aisle where the refrigerated shelves held baked goods. I noticed a slab of chocolate cake, and signaled Lyman, who happened to be with me. "Are you thinking what I'm thinking?" I said while pointing at the cake. He agreed and we decided to split it 50/50. It was at least 2lbs of cake. I said we should call it "Megacake". We put it in the cart, I paid for it and when we got back to the office we cut it in half. I ate all of my half of Megacake that night and I think Lyman did the same. COMPATIBILITY Keith was working on game 4. One day he came by my office to tell me a character in one of the fonts looked wrong. I asked him to draw just that character and scale it up so I could see whether it was the font itself or some problem with the graphics code. He did this and we could both see that one pixel was clearly one position off from where it should be. I'm a decent programmer, but I'm a better debugger. I found the problem, which was in one of the tools that processed art data to go into game ROM. It only happened when the source art, which was saved in a compressed format, happened to trigger a specific part of the decompression code in the tool in certain circumstances. This was why we hadn't seen the problem before. It was a simple fix, Keith and I verified the problem was solved and I got back to whatever I was working on before. A week or two later Tom came by my office because he'd tried to build a previous version of Star Wars Episode 1 and couldn't get the checksums from the build to match the ROM image we'd used before. That meant the ROM image was different in some way and that was concerning. Suddenly I remembered that bug fix I'd made and we reverted it locally. Sure enough, now the checksums matched! There was a character in one of that game's fonts that had the same problem but it was one we'd never actually used (probably a tilde or some other punctuation). I fixed my fix by adding an option to the tool so that you could disable the bug fix and modified the build script for Episode 1 so that it used that option. To this day I've never had to write another run-time conditional bug fix. Part 7 - How we handled playfield lamps and flashlamps The WPC games had three kinds of lighting. There were controlled lamps, flashlamps and "general illumination" or GI. The last one was strings of lights, up to five, which were just for ambient lighting. The lamps under the slingshots or by the flipper inlanes were GI. The lamps in the backbox were GI. Those strings could be dimmed when necessary, but they weren't meant to distract the player. There were up to 64 controlled lamps and the software updated them every 16ms, one column of 8 lamps per 2 milliseconds. Flashlamps were wired along with coils or motors, which meant every game could have a different number of flashlamps and they wouldn't be grouped together. The game code would list the flashlamps so that the system software knew what to show in the test menus, for example. We wouldn't have GI for Pinball 2000 and instead we doubled the number of controlled lamps. That was simpler for the electronics and the system software, and more flexible for game programmers. However, by the middle of 1998, we hadn't done anything beyond the bare minimum to update the lamps every few milliseconds. One lunchtime we were at a place called Yakzies (they had really good chicken wings) and Tom asked me if I had any idea for handling the lamps. I had a sudden bit of insight that we could use the same paradigm as we'd done for the display. The lamps were a 128 pixel monochrome display with several levels of brightness. They weren't arranged in a grid but everything else could work exactly the same. The WPC games had the concept of a "lamp effect" or "leff" although I don't think they were as sophisticated as for deffs. All the Pinball 2000 code was written in C++, which is an object-oriented programming language. The DisplayManager, Displayables, DeffManager and DisplayEffects were all C++ classes. It was easy to extend the functionality of Displayable by deriving a new class. That was what I'd done when I made Sprites. C++ also has a way to reuse source code for multiple different types of data. For example, why would you want to write two different sort routines for numbers and strings? All you'd need to do was write the tiny bit of code that compared two things and decided which one came first. This reuse comes from a feature called "template classes". The compiler would make sure you couldn't mix different types so that people couldn't try to sort numbers and strings all mixed together. My big idea was to take the display system code and turn it into templates. DisplayManager could become ViewManager, Displayable could be ViewMember, DeffManager could be EffectManager and DisplayEffect could be Effect. For lamps we could have LampManager with LampView and LeffManager with LampEffect. Almost all the code was common between both uses. The "drawing" order, effect priorities and thresholds, suspendable effects, it would mean the same things in both contexts. I derived a new Displayable from ViewMember and moved the code for copying graphics data on the display into it. Similarly I derived DisplayManager from ViewManager and put the display-specific code into it. Now I could make LampView, LampManager, LeffManager and LampEffect, and put code into them to update the low-level state of controlled lamps. Each LampView had a brightness and mask value for every lamp so that they could be composited in the right order. The brightness was one byte and every time the LampManager updated the low-level state of the lamps it would use the next bit in the byte. The more bits were set to 1 the brighter the lamp would be. That gave us nine possible brightness levels per lamp with 16ms per bit and so 128ms to cycle through the whole byte. Since that's basically an eighth of a second the lowest-but-one and highest-but-one brightnesses were flickery but still usable. The rest looked pretty good. Similarly the mask was one byte and each bit corresponded to a bit in the brightness. If the mask bit was set the brightness bit would be used and if it was clear the lamp's level would not be modified by that LampView. If you set up your mask and brightness levels carefully you could even have LampViews lighten or darken what was 'below' them in the view order. Since the lamps were equivalent to a 128 pixel display vs the 153,600 pixels of the actual video display it was fine for every LampView to specify data for all of the lamps. This was maybe two days of work and now we had a way for games to handle the lamps with just as much sophistication as for the video monitor. Even better, none of the game's display code needed to be changed at all! This restructuring of the code had an additional benefit that we never actually used. Once the concept of viewable items grouped into effects was abstracted, a game could use it for other kinds of "display". The jumping rubber martians of Revenge From Mars could've been done like that, or if another game had a second display (maybe a dot matrix LED) it would've been easy to support that too. I'm still very pleased that my solution turned out so well. I haven't mentioned how Pinball 2000 handled the flashlamps but that's because I actually don't remember what I did. I know I wrote that code because one of the anecdotes in the previous part of this series mentions the board with all the flashlamps on it. It was probably some class derived from LampView that could "animate" a flashlamp in the same way that Sprite could animate a Displayable. The Pinball 2000 diagnostics would have needed a list of the flashlamps just like the WPC test menus, so I could've used that to check it wasn't being asked to animate something that wasn't a flashlamp. Coils and flashers could be "fancy fired" where the strength would vary over time. WPC games could use that to finesse how a ball was ejected from a saucer, for example. It's also how flashlamps were made to pulse and glow smoothly. We surely would've provided the same functionality on Pinball 2000 so I could've just used that. This was over 25 years ago and while my memory's pretty good it's not perfect. I gather the source code's out there somewhere and someone else could find that part and remind me. DO NOT SEND ME ANY OF THE CODE, I DON'T HAVE PERMISSION TO LOOK AT IT. Part 8 - Graphics performance optimisation This is another highly technical episode. I had planned to have other things in here but this is long enough on its own. I'll talk about the other things later. If you have questions about this stuff go ahead and ask. I may not have explained it as clearly as I thought and it is tricky. As the game programmers and artists found more and more uses for the display, the framerate got more and more choppy. We were steadily getting faster versions of the hardware, but that only helped so much and before long we were at the limit of that. The CPU we used, the Cyrix MediaGX, was basically a turbocharged 80486. It only had 4KB of cache and was single threaded, unlike the Pentium. It was much more powerful than the 6809 CPU the WPC games used, but we were asking a lot more of it. The first motherboards we used were about 120MHz clock speed and successive iterations were quicker, but 200MHz was as fast as they got. Most of the time was being spent doing graphics things, so it was my code that needed to be improved. I spent a little time making the image decompression code faster and discussing it with Tom. Reading from ROM was slow and there were a couple of tricks to help, but the gains weren't that big. More time was being spent compositing the images to make a complete frame of video, so that was where I had to focus my attention. Generally in order to avoid a display flickering you have two framebuffers (a framebuffer is a chunk of RAM that can hold an entire video frame, so 640x240 pixels with 2 bytes per pixel for Pinball 2000). While one buffer is being displayed (which takes 16ms) you can build the next frame in the other buffer. As long as that takes less than 16ms you'll have a new, complete frame to start sending to the display once it's done with the first frame. You tell the hardware to show the other buffer and now you have a free buffer and 16ms to draw the next frame. If it takes longer than that to draw a frame you can just output that previous frame again. That's fine if each frame takes about the same amount of time to generate, but if you have a mix of faster and slower frames your framerate will be stuck at the pace of the slow frames. If you use triple-buffering you have one frame's worth of slack to catch up, but you need 50% more RAM to do that. I felt that was a good trade, and it did help smooth things out a bit. It wasn't nearly enough on its own though. We were doing all the graphics compositing purely in software, copying pixel by pixel from one place to another. The CPU could emulate VGA (a PC graphics standard at the time) but that would've been even slower, so it wasn't worth considering using directly. However, the CPU programming manual referred to a way to use a limited form of hardware acceleration. That sounded very promising, but I couldn't fully understand how it worked. Duncan came to the rescue, reading through that section and explaining the bits I'd been confused by. I was confident I could make the compositing MUCH faster. I thought about how to implement accelerated drawing, did a few experiments and was really motivated by the potential gains. I knew I'd need some uninterrupted time to get it all working, so I got up at about 2am one Monday morning and came into work. The preparation served me well and it only took a few hours of work. I was super excited about how much faster everything was. When the first other person showed up - Scott, who was always an early bird - I practically gushed at him about how it all worked. Hardware accelerated copying of graphics is usually called "blitting". The CPU could blit one line of an image at a time. It could have a "key colour" set for transparency, which meant the pure magenta I was already using for transparency just worked. We did need to reserve 1KB of the cache (so a quarter of the entire cache!) as scratch space but that was more than offset by the extra CPU cycles available for the rest of the game. I also needed to change the way we allocated memory for graphics. I'd already got the okay from Tom to use half of our 8MB of system RAM for this, so I treated the 4MB as a 1024x2048 pixel array (each pixel was 2 bytes, hence the size). It's unusual to think of RAM in this way. Because the blitting worked one row at a time there were advantages to working with this 2D layout. Most things only needed one operation to copy a row, but if the source image and/or the framebuffer row wrapped around from one side to the other the copy would have to be split into two or more sections. I was okay with that for larger things because the set-up cost of doing two copies was small compared to the time needed actually to copy the pixels, but I didn't want it to happen all the time. Allocating rectangles from a 2D chunk is a complex problem so I wasn't going to do that, but I could at least keep small images and the framebuffers from wrapping around. The top-left 640x720 pixels were the three framebuffers. The video output could have its "stride" - how many bytes to the next row of pixels - set separately from the pixel width so there was no performance penalty and the blitting code was simpler. The 384x720 area to the right of the framebuffers was used for small images (64 pixels wide or less, I think) and the remaining 1024x1328 pixels were for everything else. That way the destination of the copy was always available as a single row. Small images would have at least 5/6ths of their rows copyable in a single operation, anything 512 pixels or less would have half of its rows that way and even something wider than the screen - all the way up to 1024 pixels wide - wouldn't need more than two operations per row. I couldn't think of a reason someone would need an image that wide so I made it an error to try to create one, and I don't think anyone ever tried anyway. Things that were positioned partially off-screen or were clipped to a subset of the full source image worked almost the same, because you just copy fewer pixels and/or start partway into the row. All of this meant the code that looped through the rows to copy them was small and fit nicely in the remaining 3KB of CPU cache. Best of all, everyone would get this huge performance improvement as soon as they updated their code from source control without needing to change a single thing. I felt very good about myself that day. Part 9a - Why and how I made a whole FMV codec in a few short weeks We were well underway with the development of Revenge From Mars when another problem came to light. We only had 60MB of ROM to store every art asset the game needed. The other 4MB was reserved for an old version of the game software so that it was always possible to boot the game and upload a newer version into the Flash memory. That ROM space was filling up fast and the game wasn't even close to being done. The image compression worked well, but we needed something more. There were a few big, long animations that were using a lot of ROM space - the attract mode movie and the start of multiball were top of the list. I don't remember if the movie for Drive-In Demolition had been added yet, but that would also have been in that group. Full screen animations like that also weren't best suited to the limited colour palette our sprite compression imposed on each frame. Full Motion Video compression was still a relatively new technology in 1998. MPEG 2 was the state of the art (DVDs used it). It required a lot of computing power for decompression and even more for compression. Our CPU wouldn't have been up to the job because it didn't have the improved architecture of the Pentium, and it still needed to be handling everything else going on in the game at the same time. There might've been video codecs we could've licensed, but we didn't pursue that. We would've needed time to investigate, deal with a contract, and we would've needed source code. I decided to make a codec myself that would cater to our needs. There was no way I'd come up with something that was higher quality than already existed, but it could be good enough. I recognised that as long as the decoder was efficient there'd probably be plenty of room for improvement with the encoder. I understood enough about video compression to know that there were a few fundamental things. First, only update things that have changed since the previous frame. Second, divide the frame into square cells to take advantage of similarity within a cell. Third, you can lose a lot of information in compression as long as you're smart about it. I wanted some test video to experiment with. Our artists were busy making stuff for the game so I didn't want to bother them. I got my test data from elsewhere due to a happy accident. PlayStation games supported motion video and they used "motion JPEG" which meant each frame was encoded independently. The games also came on CDs that you could read on a PC. Final Fantasy VII had LOTS of video and someone had written a program that could extract videos from the discs. I could also use those videos to assess the quality of my codec, and directly compare the size of the compressed movie. We didn't own the copyright on the video, but we wouldn't be publishing it. It was strictly for my internal use so there wouldn't be any legal trouble. I chose a particular video for its length and content as it was a mix of highly dynamic sequences vs ones where not much was moving, or there wasn't much contrast. For those who know the game, it's the video where the player gets the Tiny Bronco - it buzzes a village, a store sign swings back and forth, the Bronco gets shot, catches fire and finally crash lands near a beach (sidenote: until I watched that video I didn't realise the game itself was rendering 3d characters over the movie!). 3D graphics was also a new technology. 3Dfx had revolutionised 3D gaming on PC and other companies were trying to catch up. There were two main 3D graphics APIs - OpenGL, which was cross-platform, and Direct3D, which was Windows-only. I kept up with this stuff because I played a lot of videogames. Microsoft were adding features to make their API better and one of them was texture compression! Their technique worked on 8x8 pixel cells and was very simple to decode. It seemed perfect for my purposes. I used this to define the compressed data format and thus separate developing the encoder from the decoder. The format generated four palette entries and encoded each of the 8x8 pixels as two bits. The big trick was that you only needed to specify two of the palette entries and the other two could be calculated from them. That meant each cell needed at most four bytes for the two palette entries and 16 bytes for the pixels for a total of 20 bytes. Uncompressed they'd be 128 bytes so that was over 6x compression on its own! In order to explain how those other two colours were calculated we need to delve into some theory, which hopefully won't be too hard to understand. Computer displays use additive colour theory. That means you start with black and add light to it. The primary colours for this are red, green and blue, which is why we talk about RGB. Printing uses subtractive colour theory, in which you start with white and add ink to absorb certain colours. The primary colours for that are cyan, magenta and yellow - which are the inverses of the additive primary colours! Now, think of a cube. It has 3 dimensions, each of which corresponds to one primary colour. The X axis (left to right) can be the amount of red, from none to saturated. The Y axis (bottom to top) can be for green, and the Z axis (front to back) can be for blue. The bottom-left-front corner will be black. The opposite corner, which is the top-right-back corner, will be white. The bottom-right-front corner will be red, and its opposite corner will be cyan. Every colour can be represented as a point somewhere in this colour cube. If you have two colours, you have two points, and if you draw a line between them you'll have a smooth colour gradient from one to the other. The reason I explained this above is because the compression picked two points in the colour cube. The other two colours were at specific points along the line between them. One intermediate colour was a third of the way from the first to the second, and the other was two thirds. So, you might have black and full red, and you'd get dark red and brighter red as the intermediate colours. Picking the colours would be complicated, but that was strictly a problem for the encoder. The decoder could grab those 20 bytes, do a bit of integer math with the first four bytes and then update the 8x8 cell in the destination image buffer. Best of all there were only 3 divide instructions needed. Division was usually quite a bit slower than multiplication on CPUs in those days. Similarly, math involving decimals ("floating point" arithmetic) was slower than integer math. Nowadays everything is so much faster that it's rarely worth worrying about. Since we used five bits for each colour channel and thus 15 bits for a whole colour, we had one spare bit in each two bytes. Two bits can have four unique meanings so I took advantage of that. In addition to the format I described above, I added a format for 2 colours where it only needed 1 bit per pixel and didn't have to calculate the intermediate colours, a format where every pixel was coloured the same since that only needed 2 bytes, and used the last meaning to skip the cell entirely. I doubt the decoder took more than a day or two to write given how simple it was. I think I asked Tom to look over my code to see if there were ways to make it faster, but I don't think he had any radical improvements. I'm sure he came up with a couple of ideas. I did add a feature to the decoder which was to decompress at double width, so you could have the source movie be 320x240 and look right on our 640x240 display. That also made it much faster since you only had to read half as much data from the ROM. The encoder was the much bigger part of this endeavour and I'll get to that with Part 9b in a couple of days! Part 9b - The FMV encoding tool My first two weeks had been a mix of doing research, getting test data and writing most of the decoder. Among that research I converted the test movie into a sprite animation. I must've used some sort of tool to do the colour reduction but I don't remember exactly how. I might've used 64 colours, just 4 levels of red, green and blue. It ran REALLY fast, but it looked AWFUL. I had a baseline and that was the important point. JPop came to see me one day and he was diplomatic when I showed him, but we both knew it would not be of an acceptable quality. I think it would've been an okay answer for monochrome things, but definitely not a general case. I had no idea what the Star Wars team were doing, but he let me know they'd be using my codec as well. I'd expected so, but I wouldn't get to see their results until everyone else did. The encoder needed to read a bunch of image files, one by one, and compare them to what had been previously encoded. Each 8x8 pixel cell needed to have some value calculated that said how 'different' it was from before. All cells above some threshold for difference would then be compressed down to 4, 2 or even 1 colour. Those colours needed to be chosen in some sensible way and the pixel data converted. The cell that had just been compressed would be updated to reflect its decompressed state because what mattered was how different it looked during playback. I needed the process to be flexible. It was important that programmers and artists could trade size and quality, and that we could add new ways to choose the colours. We also needed a way to mark certain frames as 'key frames', which meant every cell was encoded and the previous frame didn't affect things. That had two purposes. First, it meant the movie didn't always have to be played from the start. Second, movies that had scene changes (camera cuts in film terms) wouldn't have cells from the previous scene straggling along until they had changed enough to be worth updating. All of this meant I needed a bunch of command line options for the encoder. In addition I would add a simple script file that could set those options in a more friendly way. When you're trying to figure out why something's not working the way you expect it's irritating if you have to go look at what '-i 7' means vs 'keyframe-interval 7'. Bugs usually come up closer to the end of a project, when time is more precious, so time spent on things like this is helping your future self as well as your colleagues. I've never once regretted choosing to spend more effort earlier to save effort later no matter what kind of project I've worked on. In addition to all this I needed a way to specify where to get the source images from, in what order and what format. I don't really remember how I did this, but it must've been something straightforward so artists didn't have to worry about it. TGA (Truevision Targa, named after the company that invented the format) was the most likely choice because it was simple to process and lots of art tools could save TGA files. I expect they were saved into a single directory rather than a zip file or something. The order was most likely just by alphabetically sorting the filenames. As long as you use leading zeroes that works fine. Notice that a lot of these things aren't actually the primary purpose of the encoder. They're about structure and configuration. I haven't said anything about how the calculations and colour choices and conversion worked. This is the nature of software and why programmers scowl when someone says a change must be easy because you could just do this one quick little thing. Someone on the rec.games.pinball Usenet group once assumed that pinball programmers just 'filled out a bunch of numbers' or words to that effect. Sometimes one of us would derisively quote that. Be kind to your programmers. In order to figure out which cells to update, the tool had to calculate how different each cell in the current frame image was from what had previously been decoded into that cell. The idea of the colour cube from the previous part helps understand this. For each pixel, its current colour is one point in the cube and the colour that was last decoded into it is another point. If you measure the length of the line between them, do that for each pixel in the cell, add up the lengths and then take the average, you get a single value. This is how I did it, and it worked well enough although I know now it wasn't optimal. I was just taking the magnitude of the length (so it couldn't be negative) when I should have been taking the square of the length. My mistake meant a small number of high-contrast changes did not have as much impact as a larger number of more subtle changes. Anyway, every cell that had a difference value higher than the threshold value from the script (or command line) would get updated. I played around with this in prototype code that just generated solid black and white cells so I could see how well it tracked the test movie. I picked a default value for the threshold based on those experiments. Each cell that was to be updated needed two things to be decided. First, whether to use 1, 2 or 4 colours total for it. I don't remember how that was done, but I think it's a measure of how much variation there is between pixels in that 8x8 cell. I probably just calculated that and used a single colour if the variation was low enough. The other decision was the one I had the least certainty about, namely choosing those two colours. That uncertainty turned out to be very helpful in the end. I came up with several heuristics and the code would try all of them for compressing the cell. Compressing and immediately decompressing the cell followed by calculating the difference between the original cell (i.e. the one from the current frame) and the decompressed cell gives a comparison score. Whichever pair of colours scored best would be used. The first heuristic I invented tried to take several things into account, such as the different brightness levels of red, green and blue (21% vs 72% vs 7%) and I forget what else. I added some simpler ones such as the pixels with the greatest difference in red, or green, or blue. That first one turned out to be good in some circumstances, but the simpler ones outperformed it most of the time. I hadn't expected them to do so well, and having all the heuristics compete on every cell made it possible. The actual compression was straightforward by comparison. It worked through the cell, one row at a time. For each pixel it would pick the colour that was closest to it, then it would modify 'later' pixels based on how much the chosen colour differed from the actual pixel colour. For example if the chosen colour was less red than the original it would make some nearby pixels redder. This technique is called dithering by error diffusion. I learned about it in university and had written code in the past that did this, specifically Floyd-Steinberg error diffusion (the name's very memorable!). By the time I was done I had a codec that could crunch my test movie into less space than the motion JPEG format it originally used. The quality was worse, of course, but it could play back at 30Hz. The artists weren't thrilled about the overall quality of the video, but they were still happy that we could have these big, impactful movies. The main thing I had to explain to them was that it was when pixels in a single cell varied a lot in red AND green AND blue that things would look bad. For example, the mode start movies originally had a purple border around the letters. When they changed the purple to black it looked much nicer. Artists are used to thinking about colour so they understood how to work with the constraints. All of this work, from discovering we needed a specific way to handle FMV, to the codec being fully implemented, took about seven weeks. I would come to work, shut my office door, put music on and just work relentlessly. My coworkers knew to leave me alone unless it was an emergency. I was still going to lunch and dinner with people, so I could answer questions or offer advice on other graphics stuff. This was a serious time commitment given how much we had to get done for Pinball 2000, but I think we would not have been able to get something usable any other way. Part 10 - Debugging and things I accidentally broke This is the last highly technical post. It's also very long. The remainder will be about game programming and so will be much more about rules, decisions, collaborating with designers and artists and such. Tom was an expert in using emacs, much more than myself or likely anyone else on the team. He was able to hook up the debugger, gdb, to the editor so he could do source level debugging. I rarely used that because I preferred a full IDE like Visual Studio, but it was there when I needed it. He cared about making the edit-compile-reboot-test-debug cycle efficient, which meant everyone benefited even if we weren't using every option available to us. To this day I have almost no tolerance for development environments that don't provide a usable debugger. It's been 25 years since we left the 'bad old days' behind. He had also implemented a serial console. This worked like a terminal or shell. You could register commands from code and when the user entered the command from the terminal connection (over the serial cable) your code would get called. Commands could have parameters and could print debugging text to the console. I used this for almost everything I worked on. EffectManager and ViewManager had functions to print the list of Effects and ViewMembers, so derived classes like DeffManager, LeffManager, DisplayManager and LampManager could register their own commands and call those functions. This is another instance of something great in the WPC environment being rebuilt for Pinball 2000. The development setup for those games could dump out the process table and many other system structures. We did improve on it by adding custom commands. The first time I broke the code really badly was as part of adding one of these debug commands. As I mentioned in an earlier post, it's important for programs to free memory they allocate, to avoid memory leaks. When you ask the system for memory, it actually allocates a little bit more than you ask for and it uses that extra to store information about how much memory was allocated, and sometimes other things to help detect if you overrun or underrun the memory. Memory that's been freed is used to link to other free chunks of memory, so the system can scan through them to find a suitable chunk to allocate. I made a command that could traverse those free chunks and print out information about each of them. That way we could see if memory was getting broken into lots of fragments. That was fine and I think it helped us several times during later development. I decided I wanted to be able to do the same thing for allocated memory and that meant storing another value in that 'extra' information so that all the allocated memory could be traversed just like the freed memory. In turn, that meant the overall amount allocated had to be bigger and the calculations had to reflect that. I made the changes, wrote the command, tested it briefly and it seemed to work well. By then it was late at night and I did a thing that programmers should not do. I 'checked in' my code and then went home. When I arrived back at work the next morning - just about, because in those days I was arriving around 11:30am and leaving at about 2:30am - I hadn't even got to my office before George intercepted me. He asked if I was going to look at the big bug that was affecting all the programmers and make it my top priority. I had no idea what he was talking about but assured him I would do so. Anything that stops multiple other people working needs to be addressed quickly. It turned out everybody was getting non-stop crashes in all sorts of random situations. Since this was new for that day, I looked at the history in version control and the only noteworthy change was my own from earlier! This is the problem with programming while tired and without others to look at your work. I had messed up those calculations and whenever memory was freed it was likely that something else got corrupted. It was very dependent on exactly what had happened before, which is why it seemed random. I was embarrassed to have checked in code that was so straightforwardly broken, but glad it was an easy fix. It meant in future I was able to joke about it with people by saying, "at least you didn't break malloc()!". The command itself proved its use very late in development. When a game had been powered on for a week it began to get slower and slower and the playfield lights would flicker, and eventually it would crash. This happened even if no-one was actually playing the game and it was just running attract mode over and over. If we hadn't had such good debugging support this would've been a very hard bug to find since it took so long to manifest. When we hooked a laptop up to a game in this state and used the memory tracking command it showed a huge number of very small memory allocations all happening from the same bit of code. That code was part of the audit tracking, which I knew nothing about. The programmer responsible for this leak was able to identify the problem very quickly and fix the bug. That brought us one step closer to our goal of the game never having to be power cycled or rebooted. This wasn't the only thing blocking us from that goal. Very occasionally a game would crash in a highly mysterious way. It didn't seem to vary with time or circumstance, and the only information we had was that it seemed to have something to do with dividing by zero. In math, anything divided by zero is infinity, but computers don't generally have a way to handle infinity in integers. Our CPU would throw an interrupt and since we didn't catch that interrupt we would just crash. The mysterious part of this is that there weren't very many places in the code that actually did division, and the crash didn't seem to involve any of them. I took on this puzzle since I was mostly done with my other work. Interrupts are a way that a CPU can call a piece of your code and basically say "hey, this thing happened and needs to be dealt with right away". Software can generate them, and so can hardware. For example if a network card has received some data it can trigger a hardware interrupt so the system can jump straight to the packet handling code and then go back to where it was before. The code that was interrupted has no idea anything happened 'underneath' it, so to speak. I had a thick book about how interrupts worked on PCs in general and it covered our specific CPU/motherboard too. I set myself to reading and I learned that if two hardware interrupts happened close enough in succession that the interrupt code for the first one was still active, that was called a 'double fault' and threw its own interruption. I think the normal use for this is to be able to know your system is trying to do too much and do something to reset hardware or ask for some operation to be retried. We didn't have those situations so we had nothing hooked up to it. The reason I mention this behaviour is that hardware interrupts were numbered from 0 to 7 so that you could have a different handler for each kind. The software interrupts were ALSO numbered from 0 to 7. It turned out that the software interrupt for division by zero had the same number as the hardware double fault interrupt! That instantly raised my suspicion as it seemed unlikely just to be a coincidence. I probably talked about it with Tom and/or Duncan for a second opinion. Sometimes with bugs you can do things step by step or work it out with other people, but sometimes you just have to think really hard and get it right on your own. This bug was definitely in the latter category. In any event, I came up with a solution to try. I could write some code to hook to that interrupt and recover from whatever mishap was occurring. The thing was, there were two possible cases here and so two different types of recovery. If we'd actually divided by zero, we needed to skip over the CPU instruction that had done that, but if it was spurious we needed to retry the instruction. The interrupt got passed some data that led to the instruction in question, and the CPU registers involved. Since instructions, like everything CPUs work with, are just numbers with specific meanings, I could read the instruction and figure out what it was. In the Intel x86 instruction set, different instructions have different lengths, so figuring out what an instruction does and much farther ahead to move the instruction pointer can be awkward. Worse, I needed to write this code not in C++ but in assembly language, to know the compiler wouldn't try to do anything else. Writing code as low-level as this in compiled languages was especially tricky in those days. The compiler let me embed assembly language instructions in the rest of the code, so that part was easy. The code to analyse the instruction was very small so it didn't take much time to write. I made the divide-by-zero recovery skip the instruction and set the register for the result to zero. That seemed the least likely to cause problems. I made the other recovery set a flag to be checked elsewhere in the code and leave the instruction pointer where it was so that the instruction would be re-run when the interrupt handler exited. I found somewhere safe in the normal system code that I could check that flag. If it was set I could print an error message to the serial console and clear it. That way we'd have some idea if we'd really fixed the problem. I also wrote a little code that deliberately divided by zero and checked what happened with my fix enabled, or not. All of it worked as I expected. That crash seemed to stop happening and every once in a great while someone would see that error message while running their game with the console connected. I talked about the difference between good code and great code a few posts ago. One of the other programmers was working on a game mode for Revenge From Mars and struggling with aspects of its graphics due to my code only being good. It was a big step up for them from 6809 assembly language, and their expertise was in the creative side of programming. When we showed the game in Britain at the ATEI show (I think it was January 1999) we found that the game would crash in that game mode from time to time. We got around this on the show floor by power cycling the games every 45 minutes or so. Naturally the programmer in question was suspected of having caused the problem. After all, it had been the source of a lot of bugs previously, so much so that Lyman or I could just say the name of the process in question to each other to make them laugh. I tried to keep an open mind, but resolved to investigate as soon as we were back in Chicago. It wasn't too hard to reproduce the crash back in my office and I learned it was because the code was running out of a type of flag called a semaphore. These are used in programming to manage access to some resource by multiple processes. Something was allocating them but not freeing them. I either added a command to dump out all the allocated semaphores, or used one that had already been written (more likely the former, since I wrote a LOT of those commands). The code that was leaking the semaphores was written by me. It was in the innards of the effect management code, and that game mode just happened to be more likely to trigger that bit of code. I fixed it and made sure people knew that the author of that game mode had done nothing wrong. It was good we found it then, because it could've caused more problems later on. I think it's important to give credit where credit is due and to own up to my own mistakes if I'm going to feel okay telling others when their work needs to improve. During the course of Pinball 2000 we all pulled all-nighters at various times. The story of Megacake happened on one of those times, probably when we were getting ready to demo the game to senior management. The all-nighter I remember the most was just before going to Britain to show the game. I'll talk more about that in my next post, but there was one incident that belongs here. We were all adding as many things as possible to get the game in its best state for being shown, Lyman included. He was working on something that I don't remember, but almost by chance during it he decided to block the trough kickout so balls couldn't be ejected into the shooter lane. His game crashed. He tried it again and it crashed again! He called me and Tom over and we watched, horrified. To my knowledge nobody had seen this crash before and since so little else was active at the start of a ball it was probably something serious. I reproduced this in my office and discovered it was what's called a race condition. When you have two pieces of code potentially modifying the same data there's the risk of things obstructing each other or getting corrupted. Which exact order the modifications happen in each time is highly sensitive to the overall system behaviour. Specifically, a process was sometimes getting killed and its resources automatically cleaned up before it had quite finished doing whatever it was doing. I had an idea of how to fix it, but it would mean messing with the process scheduling code, which was at the heart of the system. That was dangerous at any point in development, but especially when it's the evening of one day and you've been at work since midday of the previous day. I went to an empty office and shut the door and took half an hour, just myself and the whiteboard, to think about what to do. The idea I came up with was for a process to be marked as a 'zombie'. Zombie processes couldn't run, but they wouldn't be cleaned up until the mark was removed. This was not a good solution. It was messy, and I wish I'd either not thought of it or removed it from the code entirely as soon as we got back from Britain, but I didn't. It didn't cause us later problems, but I still judge my younger self for things like this. I explained the idea to Tom and Larry (who said he couldn't believe I could think so hard after being awake for so long) and went with it. It stopped the bug for me, and for Lyman when he tested it on his game, so we called it good. I went home right after that and slept until the next afternoon, when I needed to meet the rest of the team at the airport for the flight. I think I slept on the flight as well, which isn't something I can normally do. As a side note to all that, when I'd lived in London a few years earlier it had been near Heathrow airport. That's where our flight landed so we used the same Piccadilly line train that I'd ridden so many times in the past, through the same stations. It was a strange feeling to see these familiar places in such a different context. I also remember when we got off the train it was at Russell Square station. You needed an elevator to get to street level there. Larry's wife and their first baby were with us, the baby comfortably asleep in the carrier, but when the elevator arrived it beeped loudly as the doors opened. The baby woke with such a clear look of annoyance, searching for what had disturbed its rest. Once we were in the elevator the baby went right back to sleep, all rudeness forgotten. Part 11 - What I did on Revenge From Mars The first Pinball 2000 game's theme was decided for business reasons. We knew that Attack From Mars was very successful with players and so also with operators. Making a sequel would take away an element of risk for a brand new platform like we were making. We were still early enough in development that there wasn't a strong need for a game team to get going. Pat and the mechanical and electrical engineers were busy working on the cabinet and overall design. JPop had a prototype playfield with enough elements to support system development, and he had a programmer to help with that. The Star Wars contract negotiations were in progress and that mini-team would pick up the project when ready. Lyman was working on Monster Bash and so had no time for anything else, but George was able to split his time between that game and his Pinball 2000 work. All of this meant the timelines would work out perfectly. When Lyman freed up, he could have a whitewood right away from George, and there'd be enough existing code for him to hit the ground running. He was so skilled that he'd have lots of good feedback for us and we could support him. JPop's team wasn't under the same amount of pressure so they'd be able to ramp up on their own without needing to share confidential things. We'd have hired enough artists to handle the added workload. Since Larry managed all of pinball engineering I expect this was down to his expertise. Dwight and Keith also worked on Revenge From Mars. I think Dwight was actually the first programmer since he was so creative and experienced. Keith and Duncan had both been hired, ostensibly to work on slot machines, but we all knew that it was really so they could get their shot at working on the thing they truly loved. Duncan joined the Star Wars team, and Keith was on Revenge From Mars. A WPC game usually had one programmer or sometimes two, depending on the timeline and team. It was obvious this was going to be insufficient for Pinball 2000 given the extra complexity of the games, the rough edges of the system code compared to the level of polish in the WPC system code, and the difficulty of C++ for programmers who were used to 6809 assembly language. All of this meant that once my graphics and effects code was in good shape I was needed by the RfM team. With that, the team had four programmers. The advantage of the game's design was that it had nine game modes and six of them were available at the start of the first ball. Of the remaining three, one was the question mark mode which was actually four different mini-modes. This naturally came out to two main modes and one mini-mode per programmer. Dwight did Alien Abduction and Drive-In Demolition. Keith did Paris In Peril and Mars Kneads Women and Lyman did Big-O-Beam and Tower Struggle Alien Abduction and Paris In Peril were the first two modes worked on. Dwight and Keith's needs thus guided my choices and order for system work. When I joined the team I picked up Martian Happy Hour and Secret Weapon. There was lots of other work to be done, but since I wasn't great at thinking up rules I took on a lot of the simpler things, especially ones that were necessary but not that exciting. I started with Martian Happy Hour. It was quick to get the martians in place with their drunken animations, but it needed them to interact with each other as well as the player in order to give it some personality. I spent a while choreographing their speech so it was actual joke telling and conversation. I also made the bar shake and gain scuff marks if you hit it rather than a martian. It was important to me that it felt like a physical interaction, since that was a big goal of Pinball 2000. Each mode needed a way to complete it 'flawlessly' in order to earn one of the nine lights that led to the wizard mode. I called those 'Lyman Lights'. We already had the idea for the exploding gasoline tanks over the bar, so I decided to use those for that option. I don't remember how it worked exactly, but I know it's sketchy and probably not that fun. I was happy overall with how the mode turned out though. I'm sure if George or Lyman had really wanted changes, they would've told me. Secret Weapon was originally called Weapon Envy, but George knew he wanted a mode that was like Mortal Kombat. That was why the name and concept changed to fighting a giant martian. I think it was Adam who suggested having Abraham Lincoln come to life. I don't remember who suggested the rotating pennies to mark the shots: I think it was me, but that may be wishful thinking. It was definitely my idea to do the BAM! POW! Hit reactions, inspired by the old Batman TV series. I also got the artist to use the stipple/checkboard transparency on them so they didn't fully block the martian's animation. By the time I was working on this mode the sound designer, Dan (Forden from Mortal Kombat fame), had filled the sound ROMs and was having to cull things deemed too long or not useful enough. A whole bunch of speech calls for Secret Weapon were on the chopping block and I got a bit upset about that. I didn't yell at anyone, but I did send an email to George pleading to keep enough speech that each shot could have a unique phrase. There was one especially long one where the general said something like "I didn't walk five miles barefoot through the snow just to see you give him a girly-slap! Him him harder!" and I was happy to see that one removed. I didn't think it was funny enough for being so long, although I think George liked it. Between the three of us we came to a compromise about the speech. I rarely interacted with Dan, so it wasn't a big deal and I loved the music he wrote for that mode. The fatality sequence was an FMV, transitioning from the animated sprites, and I liked the way it turned out. The actual rules for the mode were very simple. There's no combos, no secrets, no way for you to lose health (a dictate from George or Lyman), it's just make however many shots to win. You're also guaranteed a Lyman Light because I couldn't think of a way to differentiate it. It had to be done fast and like I said, I'm not particularly creative in that way. I did the Martian Bowling mini-mode and that's actually my favourite thing in terms of rules. I wanted to use the action buttons for something, since they were a new addition. I wanted to riff on Space Invaders and I wanted it to use the actual rules of bowling. Those led to shooting straight up the middle, aiming the hit cone with the action buttons and the martians moving back and forth. Exactly where the metaphorical bowling ball went in the cone had a little randomness to it, mediated by lining up the cone and the shot. Scoring used strikes and spares just like real bowling. I forget how you earn the Lyman Light, but it's probably beating a minimum score or maybe getting a strike. There wasn't a lot to it, but there didn't need to be since it was a mini-mode. There's one other gameplay feature I worked on and that is Hypno-Beam Multiball. Since Attack From Mars had Strobe Multiball, we wanted something similar that could also be triggered as a random award. George probably came up with its name and either he or Lyman had the concept, but I made it my own with the spiral graphic and effects. It was much more intense at first, it really shook and flashed brightly. Larry kept getting me to tone it down because he was worried about it affecting people. I understood his reasoning, but I thought he was being overly conservative. It's ironic because in 2004 I developed epilepsy and I'm not photosensitive! In fact only a tiny minority of epileptics are sensitive to flashing lights and so on. My other contributions were the end-of-ball bonus screen, the game over screen and the attract mode pages. I used the technique of printing the headings three times slightly offset to give highlights and lowlights. Some people weren't crazy about it at first, but everyone came around when they saw it used consistently. It helped that I'm good at picking colours. All of that work was done in a single all-nighter, I think the one before leaving for the ATEI show (the same one I mentioned in the previous part). I figured we'd replace at least some of it with more interesting pages. In the end we shipped them all without changes, and I'm proud that they were pretty enough for that. I think I got inspiration from the story of how Larry wrote the whole attract mode for Defender in one night, although that was a much more impressive task than a few screens using pre-existing fonts and animations. The bonus screen lasted longer at first, but Larry kept coming by that night and telling me to make it quicker, so I kept speeding up the count-up. Our fonts always had all the digits be the same width so that the font didn't gibber back and forth when we did those sorts of count-ups. So many games still don't do that and I always think they look ugly for not doing so. I did do two more things for RfM that weren't specific to it, both to do with graphics. They'd both been asked for more than once but I just hadn't had spare time to work on them. Every day was precious. The artists and programmers were understanding and I'm grateful they found alternative solutions until I could deal with things properly. Mars Kneads Women was done specifically because George wanted a mode where you made a shot and then watched a movie. The cartoon style of them didn't go well with the FMV codec and in any case they might have been in progress before that tech was ready. As such they used a good chunk of space in the ROM. The artists wanted the ability to have 'delta compression' in the sprite animations. That means each frame draws over the preceding frame and only changed pixels have to be compressed. It can save a lot of space. They couldn't just use the transparent colour for it because that would have prevented existing solid pixels becoming transparent in a later animation frame. I'd resisted adding this because it would mean messing with the animation format and changing the tools. Keith had been very accommodating, working to keep a minimum set of individual frames and reusing frames for loops and so on. That was messy, but I just didn't have any time to solve the problem properly until later. When I did get a bit of free time I used it to provide that functionality. I picked a part of the compressed data format that I thought wouldn't be too big a loss and repurposed it for delta compression, letting us skip sequences of pixels to be preserved rather than overwriting everything. The movies compressed better and there was no need for fiddly handpicking the frames out of order. By the way, the voice actors in those cartoons were all employees. There was a young woman whose name and job I don't remember (something to do with mechanical engineering maybe?) who did the voice for the girl with the shopping bags, and being massaged. I wonder what became of her and if she even remembers that? The other task was being able to zoom a sprite in or out when drawing it on the display. We had hardware acceleration for drawing at 1:1, but image scaling had to be done entirely in software. I deliberately hadn't supported it while doing the other graphics code, because I knew it would be slow. Any time you provide some functionality to creative people, whether programmers, artists or designers, they will find ways to use it. They'll often dream up things you didn't even realise were possible. It's very cool, but it can also be problematic if it has performance ramifications. Since we were fairly close to finishing the game the danger was low. Doing any blending or filtering would've been way too slow, so the zooming out looks a little sparkly from aliasing. Like so many Pinball 2000 things though, it was good enough for most uses. I forgot who wanted it, or what it was used for, I just know it got done. There was one other late addition. Williams' sales department was run by a guy called Joe Dillon, who'd been at the company forever. He was a recognisable face and voice to so many of our customers and their employees. Sadly, he passed away during the development of Revenge From Mars. I was asked to make an attract mode page to commemorate him. I was given the text, but I came up with the layout and style of the scrolling text. Joe was a unique individual and I'm glad I got to have my own small part in honouring his legacy. Part 12 - What I did on Star Wars Episode 1 and how we handled the secrecy requirements I did very little work on Star Wars Episode 1 specifically, but I interacted with team members throughout my time on Pinball 2000. I never forgot there was a second game in the pipeline or that it was an extremely important license for the whole company. I did my best to consult with them and explain how things worked or offer suggestions on how to best approach graphical matters. Naturally, when they found bugs, I would make sure they got the fixes as well. We could only speak in generalities. Nothing to do with the film or associated things could be disclosed outside of the team. Everyone who had access to anything to do with the film had to sign an agreement of unlimited PERSONAL liability for anything they leaked. I'm sure Williams had a similar agreement, but this was directly between individuals and Lucasfilm. I wasn't asked to sign that and I wouldn't have done so. I felt it was unfair to be expected to take on so much legal responsibility for work purposes. It must have complicated the team's communication with everyone else, but when someone has a machine that (metaphorically) prints money they will only lend it to you if you promise to take excellent care of it. The codename for the project was The Big Kahuna, or Kahuna for short. Curious people could be led to believe the game was about surfing although I don't think anyone could have made this excuse with a straight face. The team and everything they did was kept behind a locked door at one end of the pinball engineering area. The badge reader would only unlock for authorised people. This prohibition extended all the way to the very top of the company. One afternoon the CEO came up to visit and tried to get in. I happened to be nearby so I got to witness the situation. He kept zapping his badge, the door kept denying him and he kept swearing at it. He always sounded good-natured, but I always felt his tone was deliberately "ha-ha, only serious" and stayed on my guard around him. After a couple of minutes JPop heard the kerfuffle and came to the door. He cracked it open just enough to peek around the gap. They had a brief exchange with JPop saying he wasn't allowed in and I'm sure he immensely enjoyed getting to appear superior to the most powerful and ruthless person in the company. Of course the CEO wasn't in the habit of taking 'no' for an answer and he got his way after JPop's token resistance. I never heard what happened between them behind that door. Hopefully it was just as amusing as the part I witnessed. There was at least one case where something I'd included because it seemed a good idea got used by the Ep1 team first. That was the ability to encode FMV with square pixels (e.g. 320x240 for full screen) and decompress it double-width. FMVs could be any multiple of 8 pixels wide or high and so they used lots of little video clips, and integrated them with sprite animations. They told me that it had a big performance improvement to encode them like that. I like it when one of my hunches is validated. On the other hand there was at least one time that a team member got angry. Larry told me I needed to focus my attention fully on RfM and let the Ep1 team solve their own problems. I probably took him too literally when I explained to someone from that team that I couldn't accommodate a feature request, and why. We were talking over text chat and while they never insulted me, they were clearly furious. I don't remember exactly what it was they wanted and I hope I did address it later! There was a time fairly early in that game's development when JPop had to come through pinball engineering with a camcorder. Since it was the late 1990s he had a camcorder on his shoulder and was gathering footage to send to Lucasfilm. Apparently most licensees for franchises like that only get limited source material. For example, someone making toys will get a page of text and half a dozen photos, and they just work from that. The licensor has final approval so they can demand changes, but it's a low-maintenance relationship. The Ep1 team needed MUCH more information and eventually Lucasfilm asked what they were making, so he made a video showing what Pinball 2000 was and how complex the project would be. The game had so many details. For example it's the only place I've ever seen all the Jedi Council members individually named (Yarael Poof, Oppo Rancisis and Even Piell) not just Yoda and Mace Windu. The technique of using FMV as the intro to a game mode and seamlessly switching to sprite animations was pioneered by the Ep1 team. For example, the Pod Race mode is FMV until the pod racer zips up into the air and off the screen, then switches to sprites when it immediately reappears. We used that in RfM for the end of Secret Weapon and probably other places I'm forgetting, but it was because they'd already proven it could look good. I had some spare time between RfM winding down and Wizard Blocks getting started when I got the chance to do something really cool for the Ep1 team. Every Star Wars film begins with a "text crawl" where the yellow text scrolls off into the distance. It's an iconic thing. The team were trying to do this with FMV, but they said it looked really bad. The magenta key colour would get messed up by the colour error correction in individual cells and the movies took up a lot of ROM space They needed multiple versions of that movie in order to have French and German text (maybe also Spanish, I'm not sure how many languages in total). I proposed making a custom drawing routine for them. They could just print all the text into one big, tall offscreen sprite and my code would take care of the rest. This was pseudo-3D because there was no need for rotation, just one single predefined perspective. I didn't know how to do proper 3D math (I still don't) but I had a way to get the same result. I used the physics equations of motion, where time was the row index increasing up the screen, distance was the width of the row (including wider so the text could below in from beyond the sides) and velocity was the row index in the offscreen sprite. Acceleration changed the velocity and thus how many rows got skipped over time. I may be misremembering the exact details, but the concept was the text smoothly got smaller, in proportion, the further up the screen and thus the further from the viewer it was. The text was printed at full brightness and I darkened each row as I rendered it (just a logical-AND operation). I already had code to scale individual rows so I reused that. The final result of this was they could ditch the FMVs, the game didn't need any extra art at all, it could handle any edits to the text immediately, and could have drawn anything else they wanted in the same fashion. Whenever I see the game running, or I watch one of the films I always remember my own small contribution and it makes me smile. Part 13 - What I did on Wizard Blocks The last four months or so of my time at Williams are a bit of a blur. Eighteen months of intense crunch time had eaten away at my mental reserves. I didn't talk to anyone about my mental health, and I don't know who I would've talked to anyway. The people who knew me best were my colleagues and we'd all been through the wringer together. The last 25 years have seen a lot of improvements in healthcare and I'm very grateful for that. In any case, when I was offered a place on Pat's team, working on the third game, I jumped at it. I hadn't had the chance to be on a game team from start to finish, let alone with someone who'd made some of my favourite games. When I was in my last year at university I'd owned a Whirlwind and it got plenty of play in our shared student house. I hadn't had much chance to work with Louis directly, but I liked his attitude and the decisions he made on Tales Of The Arabian Nights. I figured it would be a good partnership. The first thing I did was the rules and display effects for the blocks. There were two columns, blocks dropped from above and they stacked up. The blocks themselves could be blown up one at a time at the bottom by hitting targets, or a row of two together by shooting the right ramp. That would break any blocks that were on the next-to-lowest row. There were different kinds of blocks and they had different rules. I think we started with about five different types and I have no memory of what they actually did. I wanted the blocks to feel weighty as they fell, and to be bumped upwards a little bit when one below them exploded. It was a very simple physics simulation and easy to tweak the gravity, explosive force and so on. It wasn't realistic, but it was fun. Gamers will often say they want the former, but it's just like with films. As long as what's happening seems plausible, it's better to have it be exciting even if it's not at all realistic. We could've also used the ultimate excuse of 'a wizard did it'. Pat was very clear how he wanted to use the display. Revenge From Mars and Star Wars Episode 1 had the same problem of their playfield lighting either being too dim or washing out the video image. His solution to this was to make a black metal hood that framed the left hand side of the playfield. That area had jet bumpers and could be brightly lit without the lights impinging on what the right side of the screen showed. That way we could have the stack of blocks visible all the time and it looked really good. It's the sort of thing that needs time to figure out, which is why the first two games struggled with things like that. When the blocks exploded there was a big animation, but since the blocks were all different colours I wanted the explosion to match them. I had the artists do the explosion in greyscale and I modified the 32 colour palette before playback so that it could have whatever colour scheme I wanted: black to dark grey to blue to red to light grey to white, for example. The actual animation frames lived in ROM, but the metadata for them was built into the game code, so it was easy to copy and modify and the decompression code didn't need any changes. I was doing this in code, but I could also have had the artists make a colour swatch for each type of block as a 1-by-32 pixel image and copied the palette from that. One day Ken, the general manager, came to talk to Pat and I. It was a strange conversation. He suggested we add a camera to the game so we could take the player's picture and use it for gameplay. Apparently there was an arcade game called Clone in the early 80s that would take your picture if you got the high score and put your face on the enemies when other people played the game. I heard someone mooned the camera and subsequent players had to contend with buttocks. I'm not sure if the game ever went into production. When Pat asked about how we'd afford to do this Ken waved the question away. Since we normally were so cost-sensitive I was confused by this attitude. After he was gone Pat said "I'm one of the most politically astute people in this company and I have no idea what that was about". In hindsight he might've been trying to give us a way to help him make the case to the CEO for keeping pinball going. There was too much work for just Louis and I to do, especially since the game needed to be done quickly. Star Wars wasn't selling as well as Revenge which meant the schedules for the later games were getting compressed. Duncan was brought onto our team to pick up something that had initially been for me, but I just couldn't get to. Pat wanted this little goblin guy called 'the terror' to pop up from the playfield and run around on the screen. I think he was supposed to taunt the player at times like Buzz from No Good Gofers. By this point I couldn't keep any regular schedule so I was probably hard to work with. I might show up at 8am, or not until 5pm. I remember Louis asking me about it one day and I couldn't give him a coherent answer. I was getting stuff done but my life was in shambles. I don't know what would've happened if I'd cracked under the pressure and had a full-on meltdown at work. I was at Pinball Expo on the Saturday that George gave his talk about what we'd done and what was next. The way he ended it was very downbeat and out of character and it scared me. He was not the sort of person who would ever quit if there was a chance to save things. I'd planned to go into work on Sunday, but I changed my mind. If my suspicions were right and our game was going to be canceled then pushing myself for those extra few hours would've been pointless. I spent a while thinking about it and I was a little ashamed for not going in. I really thought I was letting the team down. I learned on Monday morning that I had made the right choice. I'll talk about that day in my next post. Part 14 - October 25th, 1999 And The Aftermath I didn't sleep well that Sunday night. I only lived five miles from Williams so it was an easy drive to the gravel parking lot on the same side as 3401 N California Ave. I parked up and walked towards the front entrance, only to be met by a sea of coworkers heading in the other direction. Jose saw me and said "You might as well turn around and go home, we're all fired". George's ominous ending had come true: he must've had some notice since he was a more senior employee. There had been an all-hands meeting that I'd missed, due to being late, but that was a good thing. I don't think I could've sat calmly while listening to me and all my friends getting laid off by a smug, fake asshole who only cared about money and could never be trusted. Causing a scene wouldn't have helped myself or anyone else, but I was such an emotional mess I'd probably have stood up and yelled. Since I had a bunch of stuff in my office I headed inside. Monique, a Polish lady of a certain age who always handled the front lobby, was as impassive as ever. She was a lot like Roz in Monsters Inc (in a good way). I made my way upstairs and stopped at my office door to draw a tombstone on the little whiteboard I had hung on the wall. Then I unlocked my office and went inside for what I knew would be the very last time. I didn't care what state I left the place in as long as I got all my things out of there. I had a shelf of music CDs, some books, assorted knicknacks (my little vinyl T-Rex, whom I named Spielberg, was on my desk) and also some computer parts. Almost all of us had modified our work computers in various ways, paying for some of the parts ourselves. The IT person for pinball was incompetent, to put it mildly, so we never let them touch our development machines. I'd upgraded my optical drive to a CD burner and added a 3D accelerator. I'd also gotten more RAM and a bigger hard drive from the company, so I left those, but the machine was still mostly gutted. I was under my desk dealing with cables when someone called my name. "Who is it?" I called back without getting up to look. It was the general manager and he invited me to interview at Midway. The companies were supposed to be separate entities but the CEO ran both of them and shared knowledge between them. It was shady, but that's how those kinds of businesses were in the 1990s. Other programmers were dealing with their personal possessions and we got together to talk about what had happened. I was relieved, honestly, because my future was clear and I could have some downtime. We were all fairly wrung out after nearly two years of hellish crunch. It was also too soon to feel grief. I said that a day like this meant we should go shoot craps and drink hard liquor. I was mostly serious, but also needed an outlet for my dark humour. I'd been teetotal for nearly five years, but that would've been a one-off. There were riverboat casinos in Chicagoland at that point, and some people went regularly, but I only went occasionally. I preferred not to go out into the suburbs or drive on the highway. Some people agreed with me and once we'd all loaded up our vehicles with our personal stuff we set out. I stopped by Greg and Keith's shared house so we could unload things and consolidate down to fewer vehicles. Then we headed to the casino! I'd probably already decided my next steps by that point, which definitely included taking the rest of the year off. I doubt we talked much on that car trip since we were all still in shock about the scale and suddenness of the whole pinball organisation being shut down. In the end about a dozen of us met at the casino and we did play craps, but I might've been the only person who had a shot (of Southern Comfort, the only hard liquor I ever drank). When I got back home at the end of the day I had processed some of my emotions, but it was still a very strange feeling. I've found a lot of projects are difficult to move on from. I work so intensely and the project swells up inside my head so that it's the first thing I think about when I wake up and the last thing at night before falling asleep. Everything else gets crowded out. Sometimes I've had really good ideas in the shower because my brain never stops, but it's not really a healthy way to be. Game projects in particular get more and more intense the closer you are to shipping the game, so you're working as fast as you can to make every little thing better and to fix every last bug, and then suddenly you have nothing to do. It's like jumping off a roundabout when it's spinning at full speed. The end of pinball also had a big component of grief, and grief can't be fixed. It just has to be experienced and supported. There was one big piece of closure though, and I'm really grateful to the company and pinball's leaders for making it happen. The company didn't want to pay us cash bonuses for all the extra work we'd done, but Larry and Jim (and probably others) persuaded them to cover the cost of a trip to Disney World for us; flights, accommodation and park tickets. It was all planned and paid for before we were fired, so they couldn't cancel it. I'm sure the CEO would've done that in a heartbeat if he'd been able. The trip happened a few weeks later, I think in early December. It was a chance to celebrate the amazing things we'd created and the incredible passion and sense of purpose that had driven us. We were able to relax and reminisce and share stories over good food. I distinctly remember a bunch of us having a really good dinner in the Moroccan restaurant at Epcot, and some of us did a long behind the scenes tour of the Magic Kingdom. They explained a bunch of the tricks in staging and theming and logistics and I was fascinated. I'm extremely curious about everything, especially creative things since I've worked so much in creative fields. If you get the chance to take that tour I really recommend it. When we all flew back to Chicago we were able to say proper goodbyes. I knew that I'd never see most of the people I'd worked with again, so it was bittersweet, but it was a grace note to our endeavours and it helped my mental healing. Part 15 - What I would've done if I'd been able to make an entire game with my own vision These are my experiences as part of the Pinball 2000 team. Feel free to ask questions. I'll gather up multiple answers into one comment like I did with the initial post. Now, without further ado… I never got the chance to work on a game project from start to finish. I helped out several games during their development, mostly doing self-contained things or working on tools. I'd hoped I would get to lead the game programming on a Pinball 2000 project, but as we know things didn't last that long. I think I would've been ready by game 6 or even game 5. I want to talk about the ideas I had then, and what I might do if offered the chance now. Idea 1: Galaxy Crashers When I got back to my office after seeing the original demo of what would become Pinball 2000 I looked at the Big Bang Bar whitewood and considered what my own concept would look like. I was inspired by the humour of the Capcom game and I was a fan of the Hitchhiker's Guide To The Galaxy books. Those things swirled together into a bar called Galaxy Crashers where the signature drink had the same name. It would've been something like Milliways, and the Pan-Galactic Gargle Blaster from Hitchhiker's. I wanted the setting to be interactive, so that the ball could affect patrons in the bar and the environment itself. That's partly why, later, Martian Happy Hour had the banter and the damage to the bar. I would've had the place look different based on the day of the week - Tiki Night, maybe Thrash Night or Love Night, things like that - to emphasise the new things Pinball 2000 could offer. I wasn't planning to have the rules work differently because that would be unfair. The Premier game Cactus Jacks was another influence. I had a soft spot for that game and wanted to have characters that the player could have some sort of relationship with. I wasn't keen on having distinct modes like many other games did, especially if they were on a timer or ended when you drained. I really liked how Arabian Nights let its modes run until you met their objective. Having things that could run in parallel would've captured the anarchic atmosphere of a place like that. This was all very hazy of course, and I had no idea how the titular drink would factor into this. Idea 2: Unnamed magic theme Theater Of Magic and Pinball Magic both felt compelling to me. You could have lots of surprises and drama. No-one else had talked about a stage magic theme. I wouldn't be surprised if JPop had something planned in this vein, or maybe he would've wanted to do another Star Wars game based on what a sequel would add to the story. I don't remember anything about this potential game beyond its theme. Idea 3: Centaur This is a game concept I had while writing these posts. The Bally game from the 1980s had such a striking art style, all black and white and with the red and amber lamps. I think something edgy like that could've been a good fit for Pinball 2000. Back in the day I'd thought about what a sequel to the original might look like as a WPC game. I'd want the girl riding on Centaur to be more than just eye candy even then. Her name would be Venus and she'd be the only thing that could ruffle the hard, brutal nature of Centaur himself. He had a booming baritone voice in the Bally original, and giving her a smooth, confident, sexy voice to cut through that would be a good contrast. I see him and her being champions or elite warriors or commanders with a bunch of minions you'd build up as a resource for them. I don't have insight into whether they'd be conquerors or defenders of their own land, or who their enemies might be. Maybe it could be a road trip since he's a motorbike and there'd be encounters along the way. A mostly monochrome palette for the video images would suit the sprite and video compression. Things that were brightly coloured would really punch through the background imagery. It would need a smooth and open playfield to encourage people to flow from shot to shot and the fast ball speed would match the frenzy of combat and roaring down the highway. Idea 4: Mortal Kombat Back when Real Time Strategy videogames were becoming a more mature genre, building on games like Command & Conquer, I felt that the MK universe could be a good setting for an RTS. The different factions would lend themselves to different play styles with different unit types and advancements. Starcraft later pulled that off so well. Anyway, picking a character from a slate of MK fighters and each of them having unique aspects could keep gameplay fresh. Maybe the game could have a similar story for each character with them differing in minigames or offshoots. They would also change the gameplay the way the houses in Game Of Thrones do. This is a very rough concept. I've no idea if it would actually be any fun.