Q War - Shockwave game
At around the same time that I worked on Supremacy, I worked on another game called “Q War”.
Both were inspired by the content of Gary Rosenzweig’s Advanced Lingo for Games book. But where Supremacy was a slight refinement and rebranding of a complete game, Q War takes one behaviour (the implementation of the bullet sprites from both the “Space Invaders” and “Space Rocks” games) and builds a different game, complete with “original” graphics.
I believe I worked on Supremacy first as a learning exercise, and then started Q War. But I made Q War available first. The only hard evidence I have is the remains of the Shocklive! site in 2001:
- 8th February - Site created! Q War, a two level action shooter is playable
- 18th February - A Completely re-done Q War has been uploaded!
- 14th March - Supremacy, a new fun strategy game is now available!
The game has been submitted to the Flashpoint Archive but as of 27 May it is not yet available. It is also sort of playable directly on this site.
Gameplay
Each level puts you in control of a ship that can fly around and shoot, with limited shields that deplete as you take fire. The game supports one or two players working cooperatively.
The game is split into multiple levels, connected by a map screen between each one where you choose your next destination. Starting in the top left, the goal is to reach the bottom right. Levels can be blank, or they can contain obstacles — either an asteroid belt you need to survive for a set time, a powerful enemy station that is shooting at you, or a pair of enemy ships to defeat. Any combination of those can appear in a single level, including all three at once.
Online features
Q War features two online features.
Maps
The map is loaded from the map.txt file along side the game file on the server. An example map.txt file:
[["xxx","a1x","a1x","xxx","xs1","xxx"],
["axx","axx","axx","asx","x2x","xxx"],
["axx","xxx","xxx","axx","x1x","xxx"],
["axx","axx","xxx","xxx","x1x","xs2"]]
Firstly, that format is the default way Lingo serialised an object. That is an array of four elements, each of which is an array of six strings.
I think the game technically predates JSON (Wikipedia says it was first specified in March 2001). It certainly predates JSON being widely used for anything. As such, Director and Lingo do not support JSON and instead use their own format. However, for string arrays, the syntax just happens to be the same.
Each string controls one map cell with the following rules:
- If it contains an “a”, the level contains asteroids.
- If it contains an “s”, the level contains a station.
- If it contains a “1” the level contains one enemy ship.
- If it contains a “2” the level contains two enemy ships.
It seems the order does not matter.
The map is also absolutely required to be exactly 6×4. It just uses direct indexing and would crash otherwise (I think technically it could be bigger without a problem).
The reason the map is loaded from a file is so I could provide multiple maps. In fact, I had it so the maps were generated by a PHP script:
Complete map script
function createMap() {
mt_srand(time()^2);
$rand = mt_rand(1,4);
if ($rand <= 1) {
$a = array('x','a','a','x','x','x');
$b = array('a','a','a','a','x','x');
$c = array('a','x','x','a','x','x');
$d = array('a','a','x','x','x','x');
} elseif ($rand <=2 ) {
$a = array('x','a','x','x','x','x');
$b = array('a','a','a','a','a','x');
$c = array('x','x','a','a','a','a');
$d = array('x','x','x','x','a','a');
} elseif ($rand <=3 ) {
$a = array('x','a','a','x','a','a');
$b = array('a','a','a','x','a','a');
$c = array('x','x','a','x','x','a');
$d = array('x','x','a','a','x','a');
} elseif ($rand <=4 ) {
$a = array('x','x','a','a','a','a');
$b = array('a','x','x','x','a','a');
$c = array('a','a','a','x','x','x');
$d = array('a','a','a','a','x','x');
}
$file = fopen('map.txt', 'w');
fwrite($file, '[');
for ($j=0;$j<4;$j++) {
fwrite($file, '[');
for ($i=0;$i<6;$i++) {
if ($j == 0) {
$row[$i] = $a[$i];
} elseif ($j == 1) {
$row[$i] = $b[$i];
} elseif ($j == 2) {
$row[$i] = $c[$i];
} elseif ($j == 3) {
$row[$i] = $d[$i];
}
$rand = mt_rand(1,24);
if ($i == 5 and $j == 3) {
$row[$i] .= 's2';
} elseif ($i == 0 and $j == 0) {
$row[$i] .= 'xx';
} elseif ($rand == 1) {
$row[$i] .= '1x';
} elseif ($rand == 2) {
$row[$i] .= 'sx';
} elseif ($rand == 3) {
$row[$i] .= '1x';
} elseif ($rand == 4) {
$row[$i] .= '1x';
} elseif ($rand == 5) {
$row[$i] .= '2x';
} elseif ($rand == 6) {
$row[$i] .= '2x';
} elseif ($rand == 5) {
$row[$i] .= '1x';
} elseif ($rand == 6) {
$row[$i] .= '2x';
} elseif ($rand == 7) {
$row[$i] .= 's1';
} else {
$row[$i] .= 'xx';
}
fwrite($file, '"'.$row[$i].'"');
if ($i <> 5) {
fwrite($file, ',');
}
}
fwrite($file, ']');
if ($j <> 3) {
fwrite($file, ',');
}
}
fwrite($file, ']');
fclose($file);
}
First the layout of asteroids was chosen from four possible layouts. Then each cell had a random chance of also gaining ships and a station. Finally, the first cell is always blank, and the last cell has a station and two ships.
And astute readers may not the $rand == 5 and $rand == 6 cases duplicated. I only noticed this while writing this post.
High score table
The reason why the maps were variable is because it also had an online high score table.
You could enter your name, and it would keep track of the high scores for the current map, including keeping solo and coop separate.
There were two different implementations of the high score server script, and considering the two shows some of my developing understanding of how to design systems (if not really any serious consideration of security).
Highscore server script version 1
<?php
include('../connect.php');
if (!$mode) {
$mode = "Single";
}
if (!$player) {
$player = "<i>No Name Entered</i>";
}
if (!$score) {
$score = 120;
}
if ($score < 1000) {
$score = "0$score";
}
connect();
$sql = "SELECT * FROM qwar ORDER BY number DESC";
$result = mysql_query($sql);
$row = mysql_fetch_object($result);
$num = $row->number;
$sql = "INSERT INTO qwar_".$mode."_".$num." VALUES('$player', $score)";
$result = mysql_query($sql);
print "Done\n";
function check() {
connect();
$sql = "SELECT * FROM qwar ORDER BY number DESC";
$result = mysql_query($sql);
$row = mysql_fetch_object($result);
$time = $row->time;
$num = $row->number+1;
if ($time < time()) {
$time = $time + 604800;
$sql = "INSERT INTO qwar VALUES($time, $num)";
$result = mysql_query($sql);
$sql = "CREATE TABLE qwar_Coop_$num (name varchar(30) DEFAULT 'No name given', score smallint(5) unsigned DEFAULT '0')";
$result = mysql_query($sql);
$sql = "CREATE TABLE qwar_Single_$num (name varchar(30) DEFAULT 'No name given', score smallint(5) unsigned DEFAULT '0')";
$result = mysql_query($sql);
createMap();
}
}
?>
In the first version I hadn’t really got database design at all.
The check function was called periodically to check if a new map should be generated (probably as part of some other page load).
If 7 days (604,800 seconds) had passed I generated a new map and I created a new table for the new high scores (actually two tables; one for single and for coop) I also stored the number that was part of the name for the tables so I knew which tables to store scores in.
Other than that, I just stored the name and score into the relevant table. It relied on the amazing feature PHP had back then called register_globals which just dumped GET and POST values into variables with the same name.
This obviously meant you could just craft a very easy GET request to post whatever score you wanted. Oddly enough, I don’t think anyone actually did.
Highscore server script version 2
<?php
include('../connect.php');
if (!$mode) {
$mode = "Single";
}
if (!$player) {
$player = "<i>No Name Entered</i>";
}
if (!$score) {
$score = 120;
}
connect();
$time = time();
if ($score < 12000 and $HTTP_SERVER_VARS["REMOTE_ADDR"] <> '80.137.161.246' ) {
$sql = "INSERT INTO qwar VALUES(NULL, '$player', $score, '$mode', '$time')";
$result = mysql_query($sql);
}
print "Done\n";
?>
For version two, some things are better. Firstly, the high scores are now in a single table with extra columns of mode and time.
And… that was it. Everything else was the same.
Except for some reason I was blocking high scores from one specific IP address. I cannot remember why. Maybe someone actually did try cheating?
I did actually make one extra addition a few years later. Another parameter that identified what website you were on so it was possible to host the game in different places with unique high score tables. I even blogged about it:
Random trivia
The name
This game predates Galaxia, and as such it predates my online name “GalaxiaGuy”. Back then I used the name “Admiral Q”, a reference to the STCCG card Military Privilege which includes the quote: “Starfleet Admiral Q at your service!”
As such, I naturally named everything with a “Q”.
There are a few old posts on this blog mentioning Q War. Notably, my 2004 references spell it “QWar” rather than “Q War”. This is obviously wrong since the title screen clearly renders it as two words, but apparently past me was less bothered about such consistency.
Graphics
Unlike Supremacy, the graphics are “original”. And by original, I mean I didn’t just get them from the Lingo book and conceived of them myself. In reality they are lovingly based on existing Star Trek material.
Player ships
The player ship is the Bajoran Raider from Star Trek: Deep Space Nine. Weirdly, the original has a pair of struts connecting to the wings, but I’ve filled in the gap in the middle essentially making the wings wider.
I also added a tint to the ship which is blue and green for player one, and red and yellow for player two.
I would later reuse the ship graphic for Gravitas.
Enemy ships
Working this out took some time.
As a small aside I would like to call attention to the excellent Star Trek website Ex Astris Scientia by Bernard Schneider. In this case his Starship Gallery was an invaluable resource without which I would not have found the source of this ship.
The enemy ships are Vidiian ships, specifically the “Vidiian ship 3” from that link.
Possibly to introduce a bit more colour to the game, or maybe just to hide the source, I drastically changed the colour from the original brick red to the weird lilac cyan combo.
Enemy station
The space station is the Renegade Borg Ship from the Star Trek: The Next Generation episode Descent (the one with Lore and Hugh).
The only change I made was to make it green.
And honestly, I’ve always thought this shape makes much more sense as a station than a ship.
Asteroids
The asteroids actually are completely original creations I made in Paint Shop Pro 5, and for whatever reason I remember exactly how I made them.
- Generate some random noise.
- Apply Gaussian blur.
- “Cut out” an asteroid outline.
- Apply a circular gradient to add shadow.
- Colourise.
Fonts
The main title and menu font is Trek Generation 1, which continues my theme of using Star Trek fonts in Shockwave games.
In this specific case, it was a surprise to me. For as long as I can remember I thought I’d used Copperplate Goth Bold (which does look similar) but when I actually explored the original source, I was wrong.
The longer text is Abadi MT Condensed Light.
Galaxia branding
Like Supremacy, some time after the initial release, I added the message “Brought to you by Galaxia”. Galaxia being another game I developed.
The future
Once DirPlayer has better support for my games, one of my goals is to recreate the Shocklive! site complete with both Supremacy and Q War. This would include a new, safer high score system to replace the original.





