• entries
166
197
• views
70,438

Combat-Helo Dev Blog

## Let's Make a Game - Procedual Content Creation (part 03)

About: This is a short series for the Leadwerks community on the process of creating a simple game using procedural content.

This week we implement the map creation process discussed in part 02 then add the mesh generation and a controller to fly around our level. Then we'll have the first iteration of our procedurally generated map.

Part 01

Part 02

Starting with the Map class.

Map:Create Function...first iteration, no corridors.

Simple nested for-loop to generate a room for each cell. Each room is stored in the table Map.Room[] with dimensions, a counter for reference and a cell offset in world units.

For our example a cell is a virtual 40x40 space, our example map is made of 4 x 4 cells.

We call the function like this...

```Map:Create (407, 4 , 4 , 40 )
```

And our function definition is...

```function Map:Create( seed , xsize , ysize , cellscale , roomscale )
self.xsize = xsize
self.ysize = ysize
self.seed  = seed
self.roomscale = roomscale
math.randomseed( seed )
if roomscale == nil then
roomscale = 1.0
end
Map.roomscale = roomscale
if cellscale == nil then
cellscale = 40.0
end
Map.cellscale = cellscale
Map.roomheight = 2.0
Print("Creating map, dimensions " .. xsize .. " x " .. ysize)

-- table to store our rooms
Map.Room = {}
-- room counter
rcount = 1
for x=1,xsize do
for y=1,ysize do
if math.random() > 0.2 then
self.Room[rcount] = {}
local r = self.Room[rcount]

r.roomID = rcount
r.cellx = x
r.celly = y
r.x = math.random(cellscale)
r.y = math.random(cellscale)
r.width  = math.ceil( math.random(3 , cellscale ) )
r.length = math.ceil( math.random(3 , cellscale ) )
r.info = string.format("id %.2d cellx %.2d  celly %.2d   x:%.3d  y:%.3d   w:%d   h:%d", r.roomID , r.cellx , r.celly , r.x , r.y , r.width , r.length )
print(r.info)
rcount = rcount+1
end
end
end
self:MakeGeometry()

end
```

In the above code to reduce rooms arranged in a solid 'grid' there's a random chance that a cell skips room creation. The cell offset ( r.x and r.y ) serves to add more irregularity to the layout.

Map.roomscale and Map.cellscale: bigger number = bigger space. One scales distance between rooms, the other scales the room mesh.

After generating the geometry from such an arrangement we get this...

I've added a head-up display to show an overhead map and annotations to the screenshot to show how the distribution of rooms work. So far so good.

Perhaps worth mentioning the CELLS are ordered top to bottom then left to right. That gives you some idea that the random offset works to radically shift rooms around to avoid being too attached to the grid arrangement.

Info: CELL is a term I use to describe a container in virtual space.

Before we generate any geometry for our rooms we have all the data we need to display a map (like the one above). Debug overlays or HUDs are handy during early development and can be migrated to a finished game HUD later. All we need right now is some way to check room volumes and positioning, some info and the players position. Later we can use a second camera to draw a top-down view if required.

Another feature we want in our HUD is some flag to draw it, a position to move it about the screen and a scale so we can fit the map to the whole screen or just squeeze it into a corner. The following code does all this. X and Y is typically used as a screen-coordinate position to draw an element and s is the size in pixels to fit the map into.

If you need to re-size text as well then you need to start rendering these to a buffer but we'll avoid the extra complexity. This is often made easier with OpenGL commands but they are not exposed to Leadwerks LUA scripts (as of 2.5).

Drawing the HUD and overhead map

```function DrawHUD()
if App.showhud ~= true then return end
SetBlend(2)
SetColorf(0.1,0.3,0.1,0.3)
DrawText("ROOM DATA",22,22)
local c = string.format("RoomCount %d", #Map.Room)
DrawText(c,22,60)
local x = 40
local y = 80
for n,r in pairs(Map.Room) do
DrawText( r.info , x , y )
y = y + 16
end
x = 400
y = 80
s = 512
sx = s / (Map.cellscale * Map.xsize)
sy = s / (Map.cellscale * Map.ysize)

--DrawLine(x,y,x+s,y) DrawLine(x+s,y,x+s,y+s) DrawLine(x+s,y+s,x,y+s) DrawLine(x,y+s,x,y)
for n=0,Map.xsize do
DrawLine(x + (n*Map.cellscale*sx) , y , x + (n*Map.cellscale*sx) , y + s)
end
for n=0,Map.ysize do
DrawLine(x , y + (n*Map.cellscale*sy) , x + s , y + (n*Map.cellscale*sy))
end
-- sorry for the fiddly math here
-- its needed to match the map scale with the HUD display scale
for n,r in pairs(Map.Room) do
local roomx =  x + (( r.x + (r.cellx-1)*Map.cellscale) *sx )
local roomy =  y + (( r.y + (r.celly-1)*Map.cellscale) *sy )

DrawRect( roomx  , roomy , r.width * sx, r.length * sy )
DrawText(string.format("%.2d",r.roomID), roomx + ((r.width*sx)*0.5)-8 , roomy + ((r.length*sx)*0.5)-9 )
end
DrawText(string.format("view co-ords x:%d y:%d", camera.position.x , camera.position.z) , 40, GraphicsHeight() - 20 )
-- player marker cross in yellow
SetColorf(0.3,0.3,0.1,0.3)
DrawText("X", x + (camera.position.x * sx)-4 , y - (camera.position.z * sy) -8  )
SetBlend(0)
end
```

The map size is adjusted by changing "s = 512" to however many pixels across. Objects are scaled and drawn accordingly. Once we start merging rooms this will need some alteration, the overhead camera might be a viable alternative and one we can have some fun with.

randomly flagged tile data, looks like a "BallBlazer" level.

Tiles and Geometry

Rather than write up how it works you can look through the code and tinker with it. The next and penultimate part will cover generating corridors and using "tile" data to merge overlapping rooms and add props like doors. You'll see already there are random light sources assigned to each room, random assortments of props such as columns, crates, particles etc. can be done in a similar fashion.

I've attached the full code which creates the room data and geometry (sans no corridors and intelligent tile merging - we'll deal with that in part 04).

Don't forget to execute this script using ScriptEditor.exe (or run it with ENGINE.EXE) you will need to make sure the path at the top of START.LUA (MediaDir) points to your Leadwerks SDK location and the default scripts are present (as "required" at the top of the script).

You'll find a few bits of code commented out and older functions I used to create meshes. I've left them in for curiosity (learning and laughter).

Until part 04, have a good weekend.

## Let's Make a Game - Procedual Content Creation (part 02)

About: This is a short series for the Leadwerks community on the process of creating a simple game using procedural content.

In part 01 we looked at one theory of generating random maps in the style of old school dungeon crawlers. This week we'll put that into practice to generate map data, room geometry and mesh colliders. The easy part was adding a flying physics based camera to act as our first-person flown "spaceship".

Again I want to flag I'm not a LUA expert, this is not a LUA tutorial but like most languages they are a syntax away from common functionality. It includes examples and explanations of some LUA code to relate why I did something a certain way. What you see is what you get. All code is freely available for use and modification however you see fit.

How to use the code and run any examples in this series

After working on the code a short time I found using the
better for the process rather than attempting to run and debug it as an editor script. And one last note before we get on with it, 99% of the assets are included the Leadwerks SDK media folder so please edit the "MediaDir" in the LUA source. Any other required media will be included as a download.

Pre-amble over with. Lets get to it.

Map Data to 3D Geometry - first experiment

The focus for this tutorial is generating map data then creating 3D geometry from it. The latter raised several questions about what would work for a tutorial and flexibility for use in different kinds of games. So I've focused more on this side for part 02. (Also I had to re-write it meaning less time to work on the map data code).

My first room generator working prototype created "shoe boxes" as pictured below. With lighting, ambient sounds and the physics on a controller to fly your 'ship' around in first-person view it was a passable bit of code.

figure 2.2 - "ShoeBox" room and corridor structure

"ShoeBox" was efficient in that it was a collection of flipped volumes with light sources, individually painted surfaces (6 materials) and would be good for a simple iPhone adventure.

When it came to merging volumes for more complex rooms I realised there would be a lot of code needed to split up geometry and re-build it. Rather than turn it into an exploration of CSG, triangulation and mesh simplification (which is not trivial) I ditched it for another simpler approach.

Going back to how 2D games work, room geometry became a collection of grids (figure 2.2) that can be thought of in terms of traditional 'tiles'.

figure 2.2 - tiled room (aka a regular mesh)

Looking more like a terrain mesh with walls and roof, the grid structure makes it easier to merge volumes, add doors, corridors and holes traps or vertical shafts. And by increasing the mesh density and adding vertex noise you can turn rooms into caves with bumpy walls. I felt justified in presenting this method as it allows more possibilities and simplifies geometry construction.

In appearance it's quite like old-school cells and tiles, similar to existing 2D dungeon map generators. In my working prototype you can't individually paint a tile but it might be possible to modify the code to allow for UV painting and save out this data. Each room can have it's own unique set of materials.

LUA code-time. Geometry Construction

Leadwerks like other engines provides tools to create solid shapes entirely in code. First you need to create a Mesh object then a Surface object attached to that Mesh.

```local room = {}
room.mesh = CreateMesh()
room.surface = CreateSurface(room.mesh)
```

Note: For clarity this is using ONE surface, this will be expanded to use a six surfaces for each side of the room. The important part is that you add geometry to surfaces, you paint surfaces with materials, you create colliders with surfaces. It's all about the surfaces baby.

All room elements such as walls, floor, lights, props etc. are parented to the room.mesh which is positioned in world space. Moving the room is as simple as calling Map:Room[id].SetPosition(x,y,z)

Really evil dungeon masters might want to re-position a room with players inside. Well you can do that, even rotate it. Parent the room to the whole map (which has a pivot) and you can roll the entire map around for a marble game. All walls are solid but as they are one sided you can see right through them when viewing from outside.

Patch Maker

Let's look at a LUA code snippet for creating the roof and floor mesh, I want to draw attention to one of the cute things LUA can do and if you've not come across it before it can be confusing. So I draw your attention to it now. The assignment of (nameless) functions to a table and indexing them by string.

Depending on what part of the room we are building we take care vertices are wound the correct way and the vertex normals are perpendicular. So I put the AddVertex() and AddTriangle() calls into a table and for ease of identification indexed them by string such as "roof", "floor", "north_wall" (walls not included here for clarity).

```addvert["floor"] = function (s,x,y,height,xsize,ysize) return s:AddVertex ( Vec3( x-(xsize * 0.5), height , y-(ysize *0.5) ) , Vec3( 0 ,  1 ,  0 ) , Vec2(x / (ysize*0.1), 1.0- y/(xsize*0.1)) ) end
addvert["roof"]  = function (s,x,y,height,xsize,ysize) return s:AddVertex ( Vec3( x-(xsize * 0.5), height , y-(ysize *0.5) ) , Vec3( 0 , -1 ,  0 ) , Vec2(x / (ysize*0.1), 1.0- y/(xsize*0.1)) ) end
addtris["floor"] = function (s,v,ysize) s:AddTriangle ( v-ysize-1, v , v-1  ) s:AddTriangle ( v-ysize-2 , v-ysize-1 , v-1 ) end
addtris["roof"]  = function (s,v,ysize) s:AddTriangle ( v-1, v , v-ysize-1  ) s:AddTriangle ( v-1 , v-ysize-1 , v-ysize-2 ) end

function Map:CreatePatch( surface , width , length , height , mode )
for x=0,width do
for y=0,length do
-- we degenerate first row and column when making a grid
if ((y>0) and (x>0)) then
end
end
end
end

```

Our room geometry code needs to call the patch builder with dimensions and the name of the component like thus...

```-- example useage from the room builder
Map:CreatePatch(room.surface, 8 , 8 , 0 , "floor")
Map:CreatePatch(room.surface, 8 , 8 , 2 , "roof")
```

That's the easy part. We will need to extend Map:CreatePatch to take our merged room data and generate an appropriate mesh to fit the irregular shape of our rooms and corridors as supplied by our dungeon creator.

Now we have a method to generate basic rooms which is easy to modify we can look at the other problem; creating our random map.

Remember the map structure we're looking for, a grid of cells into which we position at random offsets a regular set of rooms (see figure below). Each room being of variable size and can overlap. For this part of the tutorial we're going to keep the rooms small enough to prevent overlap to keep the source size down and reduce the complexity. We'll cover triangulation for a more advanced geometry function in a later part. In other words I couldn't get it to work properly in the time allotted.

figure 2.3 - room and corridor structure

We'll begin with a creator function...

```-- function to build entire map
--  params: random seed value, xsize and ysize (dimensions of map in cells)
--  roomscale (is multiplier of room size in world units)
function Map:Create( seed , xsize , ysize , roomscale )
math.randomseed( seed )
if roomscale == nil then
roomscale = 1.0
end
Map.roomscale = roomscale
Map.roomheight = 2.0
Print("Creating map, dimensions " .. xsize .. " x " .. ysize)
-- table to store our rooms
Map.Rooms = {}
...
...
end
```

For our dynamically generated game level, we need to know a couple of things;

• How big in game cells (how many rooms across and down)
• The seed from which the random nature of all springs forth (how poetic)
• How big we want the rooms to be relative to each game cell (room scale).

A tile is simply a value stored in a 2D array e.g. tile[x,y]

Our data would benefit from being organised into a grid. A 2D tile structure which represents an overhead view of our 3D world. This makes tile arrangement makes it simple to merge rooms and corridors, flag as walls, doors, traps and anything else we might want to generate. However...(c'mon you knew that was coming)...

If we want to make really HUGE levels then array mapping will be inefficient, the 400x400 grid in our example will be fine but anything larger will become resource hungry as we increase the world size. Much of it becomes empty space.

To avoid unnecessary memory usage and run-time costs we will virtualise the space a little. We've done it already with our room nodes (figure 2.4)

figure 2.4 - room nodes
are
virtualised rooms

Note: A room object simply exists at world_x, world_y and is this >< big. This is for boundary test and positioning.

We will use a 2D array of tiles for each room. Each tile maps to a room_x, room_y. This way the data is available to game logic for locating objects, spawn points.

After room generation is complete we run a post processing function to merge rooms, this is where the tile array comes in handy.

The room merge steps through all rooms, a boundary check is performed on neighbours and merging into a new room as needed. Corridors are considered rooms (just thin), where they bend they are in fact two overlapping rooms and should be merged during the same process.

After rooms have been merged, the geometry builder works on the new set of room tiles to spit out all the required meshes, lights and props.

Infinite Power!

In theory we can make an infinite dungeon if we move the rooms around us at the origin and use world space as a random seed for new rooms. An order of magnitude more advanced than Very Big Cave Adventure.

```10 PRINT "You are in a cave (N,S,E,W)?"
20 INPUT a\$
30 GOTO 10
```

Out of time!

Yes I've run out of time for part 02 due to code re-writes. I'll write up the room generator code as part 03 and post the example code with it. Then we'll start to see the two halves coming together and creating our procedural maps.

First pass on HUD to show location of rooms (with ID) within the randomly generated map complex.

## Let's Make a Game - Procedual Content Creation (part 01)

About: This is a short series for the Leadwerks community on the process of creating a simple game using procedural content.

A short while ago I was approached to write a book on terrain generation using dedicated tools for a variety of game engines. There's a lot more to game content than just terrains. Josh's recent blogs on CSG got me thinking about one of my favourite games and had me itching to re-visit the genre.

This series is an exploration of topics I don't normally exercise but are fun to do. Leadwerks is a fun engine that's ideal for prototyping ideas. So throw out your terrain system, we're going to make a game all about claustrophobia. We're going DOWN into the tunnels to blow stuff up Leadwerks style using a mix of old-school gaming know how and modern day 3D.

Our goal: create a simple six degrees of freedom shooter set in a procedurally generated network of rooms and corridors. You can use this as the basis for a number of different games but as I'm a fan of the old classic shooter "Descent" and it's easy to create a physics controller to fly around in Leadwerks. Also it can be re-worked using Leadwerks3Ds CSG functions when it's available.

Procedural Map Generation

Dungeoneering is back in gaming news with Legend of Grimrock, a take on Dungeon Master grid based geometry. Many games are based on grids, they are easy to work with and often form the basis of AI routines. They are also easy to generate geometry for. There have already been numerous articles and blogs on creating such levels, you'll find links at the bottom of this article.

True Story: The Survival horror Amiga game Xenomorph copied the same gridded dungeon mechanics in a blatant rip-off of the Alien universe where stone walls were replaced by ship corridors. Coded by an ex-Microprose employee I visited his house somewhere in Devon many years ago. He revealed that many of the game objects I clung onto for dear life had no function whatsoever. Lesson learned: Don't explain everything, keep the mystery, it's dishonest but more fun for the player.

But before we look at some LUA code to create geometry we'll first have a taster of different techniques used in creating random level geometry. After that we'll kick things up by adding more vertical elements for our demo game. I warn you in advance, I'm not a LUA expert and nor am I a big fan but I'm sure you good folks can make it better and LUA brings the examples to the widest possible audience.

Node based grid

Our goal is to create a collection of rooms connected by corridors through which we can explore. A simple approach is to seed a random number of nodes (rooms) and connect them up. There are other methods, such as a corridor based approach which adds rooms in a second pass, such a method is used in the classic DOS game HACK (aka NETHACK).

For our examples we'll stick to a 40 x 40 grid to keep it simple. Each grid square could equate 100 world units or 10 in Leadwerks, it doesn't matter as long as we use a consistent scale. We'll stick to 100 units (1 unit = 1 meter) per grid square for this example meaning our potential map is 400x400 units.

Here each node represents a room of random size. We can restrict the size of the room to fit within its parent grid to make it easier to deal with problem of overlapping rooms as illustrated in the figure below. Eventually we'll construct the geometry to build these irregular shaped rooms so they merge as a single entity.

You can see that choosing the size of rooms will impact on how much corridor space you're going to end up with per map. This is something you can set in code easily giving control over how open or closed your level will feel.

If we stick to the grid arrangement connecting them by corridors becomes an easy process. The difficult part is constructing the vertices and triangles to fit together nicely but we'll get to that. By far the easiest way of joining rooms together is by joining them at the cardinal points of the room. While this makes logic easy it also makes for a pretty boring layout. What's more, there's no reason why a corridor has to be of fixed width...or height.

A room typically connects to a room in a neighbouring grid using the straightest link possible and we'll dog leg corridors as required. To add some interest we'll create a 'route' through the grid and randomly connect to neighbours.

Again there are many ways you can do this and I encourage you to try your own variations. Our rule-set will have a random chance of connecting to a neighbour if that room. That chance will degrade if that room overlaps and on the number of existing corridor links. Hopefully our final 2D layout will approximate the figure below.

Then each room can add its own flavour by adding columns, point lights, props, whatever fits your game.

Once we've got a class to generate the map we can then move on to generating the required geometry (surfaces) so we end up with something looking like...

Things get even more exciting when we'll extend these maps into 3D, with vertically offset rooms and corridors. Eventually we'll have a complete base generated by a single random seed you can fly, shoot, leap, run through with a basic controller.

Once we make the logic for generating rooms 'furniture' props can be parented to the room mesh to take advantage of culling. I'm not going to add much in the way of occlusion, instead Leadwerks can take the stain and should do a good job with no effort on our part.

In part 2 we'll start with some code to generate the above with geometry directly in the Leadwerks editor and we'll be using Vertex and Surface commands to create rooms which look like the screen-shot below.

Random room generation in LUA, corridors coming shortly for part 2

Everyone is welcome to contribute.

Procedural Content Wiki

Generating Random Dungeons

## Mobiles, mobs and states

While waiting on fixes for the flight-model and control inputs, putting some game into the game we talked about ranges and how performance measuring was going to work. In addition we wanted to add a little variety which required working mob AI.

So nothing fancy but I managed to rustle up a simple finite state machine FSM to get some tanks and cars running around. Our design uses a group formation system (a group is a number of individual units that share common logic, e.g a tank platoon) and if you've ever used Missioneer you'll be familiar with the concept.

Currently tanks are driving around a small test tool I'm using to test the module, switching formations, revving engines, exhaust smoke. Performance is king so updates are interlaced, no vehicle physics are required so animation suffices.

Each group member has a goal pivot, when the formation changes the individual vehicles seek their pilot according to their driving behaviour. All the pivots are parented to a master pivot controlled by the group. This way you just need to update the group position (e.g movement orders to x/y) and the rest takes care of itself.

We can look into expanding the states later when we want them to do more complicated things, and do that on a per unit basis. Tank gunners will want to turret to target when attacking, manpads will simply turn to face. Same state but slightly different logic per unit. And this can be done in LUA level by setting the models "fsm_mode" key. That makes less work for me and gives Dave the artist some nice toys to play with. At the end of the day I at least have a tile based tank engine to play with. I'll throw up a video.

For the gunnery range we don't need anything demanding; some AI road following traffic, people in groups and the odd vehicle following a set of waypoints. Nothing spectacular or difficult there. That hardest part is turning the 3D geometry of the road network into a navigation grid. Then your mob groups need to know if they are supposed to be following the road or their own formation (switching as they move from one to the other).

The one problem I have in getting AI traffic running around is putting together a nav-grid I can work with. Our roads are large models (2 or 3 assorted) that are built in 3D Max using a height deformation modifier (the same height-map used to build terrain layers). And it mostly fits. I think we need to flatten it out so only the surface triangles can be read and turned into usable data.

Speaking of art, "Mossie" has been given some love.

Source

## Mossie concept art

Just a short post since I'm busy being pulled in a dozen different directions; I got roped into helping someone create a short health and safety film, drafting a project proposal, raising finances and even managed to fix a long standing bug in Combat-Helo. Now the sensors, line of sight and all that guff is now WORKING again, Hooray. A quick background on that, an engine update needed to fix some occlusion issues slightly changed the Model hierarchy in a subtle way that changed how actual filenames of models were retrieved, long story short, they no longer matched the ones in the vehicle database as they had "lod1" suffixed to everything . But hey it was a quick fix once traced, I digress as usual.

Talented Paolo, creator of many a fine mascot has been working on some fictional nose-art and patches for the squad mascot in Combat-Helo. We knew we wanted it to feature a mosquito, the mosquito is the nickname allegedly given to the AH-64D by Taliban forces. Incidentally it was also the aircraft my father was attached to during World War II so I felt it had a double meaning.

The character will be visible on squad patches and eventually be available as nose-art.

Below is an earlier draft of "Mossie" to help decide on nose style, the nose later became the Apache's signature Bushmaster cannon.

Please post your thoughts and comments on "mossie", suggestions for what he can hold in his left hand are invited.

Source

## US Army presents "Mast Bumping"

I know it's a little late for Valentines Day. Excessive flapping, bumping and separation is discussed in this priceless US Army video from 1980. If only they had "RotorCam ™". The Apache has a fixed rotor, mast bumping isn't an issue but it's all part of helicopter theory.

I've been forced to continue hunting for other employment to deal with a mounting debt crisis. As a result work was put on hold the past two weeks (hence the lack of updates). I apologise for letting my post slide, the project really is taking a toll. I've been ordered to get back to Combat-Helo ASAP (taxes and all that business stuff needed to be done too), I'll be updating as well as I can. There's an engine update to finish rolling into the project (I started on that earlier in the week, this fixes a problem with terrain and I hope the EntityUserData and hierarchy problem).

A Twitter follower suggested I post some Gun Cam footage, I had a look at that and found vegetation range/LOD issues in the MTADS camera need dynamic adjusting (not sure what the most efficient method will be yet).

I'll just round this entry off by stating that raising funds in the UK for technical entertainment projects is very difficult if not near impossible. Bank staff/accountants take one look at video of Apache cockpits and give you funny looks like you're some kind of gun nut (that actually happened).

In the meantime, enjoy the technical detail of the above video.

## Stuff you thought was going to be simple but wasn't

Swimming was one.

Setting up controllers in XPlane is another.

Yes the things you thought were going to take a few days which turned into a week and a bit (you could almost say 'two weeks'). Josh at Leadwerks gave me a leg-up on how to put an MMO style launcher together and I've almost done wrapping up all the security for the necessary database, key code generation, CVS style updates and all the stuff we need to match individual content to clients. We'll make available downloadable content (DLC) such as new maps and the occasional helicopter (the planned CH-47D), not to mention the odd mission pack.

No, this key won't work, it's a fakeSo there was a lot to do to make a simple one shot MMO style launcher. The back-end server stuff had to be built from scratch. The launch .EXE calls home, applies on-demand updates and preps game settings for launch. For simple security sakes I layered server-side scripts for handling the updates, admin and audit. Auditing is handled by triggers, SQL injection is futile since only one procedure is exposed to clients.

Any DBA will tell you Auditing is an important part of any security. If you build any kind of database exposed to the internet and you don't build your own layer on top of any default transaction logging then you're kind of asking for trouble. The database engine used here is not known for keeping detailed logs so it was necessary to build one anyway. Things you might want to think about if you ever need to create systems like these are making log indexes suitable for frequency analysis (this one method Twitter uses to spot spamming), fake open doors and keys and silent alarms. My favourite trick in the past was a fake database that gives the intruder a high and makes them believe they have walked away with the crown jewels while evidence is collected. That sort of none-sense is not required here, I kept this one functional with a tiny footprint.

The Pilot ID we'll be sending out is the key to your content; install once, play as you like. If you share copies around on your network you can launch 'offline' no worries, no need to be connected to the internet until you want to update. It's nice if you want to buy multiple copies for your network and support the effort put into this project but I'm poor too so I know how it is.

Little bit of script consolidation and testing to do before we let this loose in the real world.

Source

## Nothing serious but one reader sent in this...

From an Australian gaming mag (and those guys are tough cookies) at the bottom of a review of Take On Helicopters...

Thanks for the mention guys the picture is a bit out of date though, but what the hell.

Source

## New scratch built industrial buildings

It was over a year ago we were notified that some of the models we had purchased from Dexsoft might possibly have been stolen. After a period of investigation the probability was quite high this was the case and Dexsoft contacted customers to offer new packs. However months later I was unable to get a reply about these replacements and only in November when doing a review of outstanding assets and licensing we had to either press again or do a re-build.

Dave elected to take it upon himself to do a rebuild and not wanting to have to reposition every building adopted the same dimensions with the exception of adding much needed 'basements' (a basement is just an extrusion of the exterior wall so that it will sink under terrain so no gaps are left if the centre of the model is positioned on uneven ground.

Originally the models were made for use in first-person games and LOD0 had details such as railings and girders. Dave completely built (from scratch) versions complete with new textures and made them more efficient at the cost of some detail. An original building had 5213 polygons, after a rebuild only 728 polys (which is iPhone territory).

Original stolen model on left, rebuilt from scratch on right

Scratch build on left, original on rightAny small indie developer takes a leap of faith when purchasing models from 3rd parties, you don't know where they came from or their history. In this instance we got bitten as did the 3rd party which handled the situation well (but it would have been nice to have the replacements anyway). No harm was done, anyone using or releasing games with 3rd party content be aware.

Thanks Dave for once again being on the ball.

Update

Started work on the updater again.This is based in part on the Leadwerks SDK downloader which is pretty much everything I needed given a little twist and a slice of lemon. Hopefully some of you will be seeing this in the near future. At some point we'll add user names and a regcode system prior to any content downloads (these will not be required to play).

As much as you might want to click on it, you can't yet

With any luck the 'one click' update system will let us add rolling improvements at the cost of occasionally annoying you with a download when an update is available. I just want to be able to push one button, get the latest changes to any content I own and go.

Support for different builds (content)

Source

## Happy New Year - Another year older...

I (Richard H) take the opportunity to indulge myself in a little year-end editorial and pick out some of the personal highs and lows of the past twelve months. Warning: may contain rambling, digression and woeful inaccuracies.

Is it over already? What happened this year?

2011 a year where the most wanted man in America was shot (along with 4 other people that nobody seems to remember) by US Navy SEALs. A year where governments attempted to convince themselves they have any kind of control over economies despite the billions spent on technology and infrastructure to remove people out of the loop. I call blasting away mountains to improve packet travel time by mere milliseconds pretty compelling evidence of the forces being thrown into this new hi-tech computer based trading war. When the speed of light is too slow to make money over the competition and shortening your cable by removing hillsides is the difference between profit and loss what chance do governments or people have in this trading scenario? And it's all happening without much talk or opposition.

The 'adventure' in IRAQ was laid to rest with US President Obama announcing US troop withdrawal. The British army was there in the first half of the previous century and didn't fare much better, although the suggestion that using poison gas on rebels in the north was not acted upon, that was one of Winston Churchill's bright ideas curiously. Always seemed ironic that.

Freedom swept across the middle east, starting with Tunisia as despot after despot was felled in popular uprisings. You'd be forgiven for thinking it was some sort of Facebook game.

Earthquakes and devestation

Japan moved 20 meters westerly and horrific scenes of coastal devastation were broadcast live as the resulting tsunami from the massive undersea earthquakes swept away generations of familes, homes and soon after any remaining nuclear power comfort zone.

Japan has never been a stranger to holocaust, scenes and stories of annihilation and devastation are popular in Japanese culture, see the opening scene of Akira. This is something they have lived through time and time again. My late father-in-law was a Hiroshima survivor, sponsored by US scientists after the war he became a US citizen and then a notable scientist and Quaker. He told me once of thanking Oppenheimer (at a conference) for ending the war in his country, how awful must things have been when getting nuked and loosing your family was in retrospect the better option? It's something I can't even begin to think about without breaking down in tears.

Game devs want more pie

It was the year every game studio and his dog decided they wanted a slice of the Mincecraft pie without any consideration of what makes it so popular. The phrase "just like Warcraft" was replaced by "just like Minecraft", or if you're an unethical developer, "Just like Farmville".

Unethical is a strong word to use but I'll use it for any type of game that preys on innate human weaknesses to make you play them rather than well designed gameplay. This can be aimed at a lot of games that exist in the social arena. I blame a large part of this down to the adoption of the "Monthly Active User" metric being used as a key performance indicator (KPI) for IP acquisition and exploitation.

Another example of game success passed around developers is "Angry Birds". What they often don't realise is Angry Birds was not an out of the blue success, the creators had built up experience working on around 50 games between them prior to launch. The game mechanics are stupefying simple, any programmer or user of Little Big Planet can put such a game together. It is no more sophisticated than Gorillas (shipped as BASIC source code with MSDOS 5 see wiki), it is a single player artillery game. But everything surrounding the mechanics is a finely tuned presentation based on their collective game experience. It takes experienced designers to make Angry Birds, not programmers.

Indie because we say so

Somehow the meaning of 'indie' became fluid, when news of companies like EA announce the formation of an indie studio to engage social and mobile spaces it has one reaching for my "WTF?" stamp. In what way is this indie? Indie is folks trying to democratise games in a way big studios have been blocking for years, indie is independent thought in the game-space or some pretentious twaddle like that. Indie is not trading on skin deep looks, big bucks advertising budgets but game mechanics and freedom to experiment. Freedom to fail.

Start-ups being handed hundreds of thousands of pounds in government grants could be said to be independent. Certainly this year saw many studios spring forth from magic money with little to show for it, and some priced beyond reason. It smells of the dot com boom bust of the early 2000s. Studios are good at being handed funds (in the words of Lord Stark) 'when it's safe'. Hey investors, how about taking some risks on real projects? We could have done this bloody game in half the time, does that smack of enough bitterness? Yes I'm bitter. OK that's enough, better now. Moving on to some of the personal gaming highs this year.

Video game highlights of 2011

Shogun 2 - Creative Assembly

Assassins Creed Revelations - Ubisoft

Most of the games I had time to play this year (and that's not many) were a mixed bag. To be fair even Assassins Creed was a face-roll fest (not much skill required) but managed to keep one going through sheer story and production value. At the opposite end is Shogun 2, Creative Assembly's triumph combining many elements they've tinkered with in previous games and spades of neat game elements into their two tier strategy game packed with historical facts.

Magika is a hilarious indie action game where blowing yourself up in interesting ways seems par for the course. It came out of nowhere and fair to describe the tone of the game as something you'd get if you threw Reservoir Dogs, Lord of the Rings and Monty Python into a blender. Thanks guys for the laughs.

Honorary mentions: Battlefield 3, Portal 2. and Kerbal Space Program. That latter being great fun if you're into building your own monstrous launch systems and killing space crews in spectacular fireballs.

Video game disappointments of 2011

I bought 'em, played 'em, felt gutted.

Test Drive 2 Unlimted - Eden Games

Wow, after the brilliant but only slightly flawed first game they didn't need to do very much to make the second game a winner. It was like the anticipation of a new Star Wars film (The Phantom Menace), in the words of Harry Plinkett, how hard is it to screw up? It's like mashed potato, just add water. Well they managed it IN SPADES by populating the game entirely with really awful people. I don't want to play these characters, I don't want to interact with these characters. One forum poster dubbed it "Douche-bag simulator".

Skyrim

An honorary arrow in the knee because Oblivion with a face-lift seemed cool at first, erm how much was spent on this? Disappointment still ringing from the hours I put into Oblivion only to find the openness of character development can result in halting any progression after xxx hours. They filmed this live action trailer which could be for anything, my step-son suggested that it could work as a dandruff commercial, see for yourself...

Let me know if you hit the same wall in Skyrim.

Batman Arkham City

I finished the first Batman game a total of FIVE times. I can't think when I've ever bothered to do that with any other console game. Finishing ONCE is a rare thing.

Arkham City lost me after a weekend of play. Too much freedom and visual clutter spoiling an otherwise masterfully visualised city environment. Riddler on the Roof, he's painted dayglow green **** everywhere to solve his collection meta-quest. And worse, there's really no logic to some of the puzzles, (the rooftop chicken run with the magnetic ball for one), I can absorb bullets but I can't rip open a chicken run to grab the ball and stick it in the hole? Put me in the game like you did with Arkham Asylum please, but ill-considered content like this kept taking me out. Sometimes less is more. The artwork is amazing and the laser effects best I've ever seen, a real visual treat with jarring game elements that kill pacing.

Combat-Helo

I had to mention this. Still not out yet and my internal build seems so close yet needs more cowbell. I was really looking forward to seeing a beta released around now and spending my time apologising in public forums and working on improvements. What happened is a series of poor choices on my part which I wouldn't choose to do again. Problem that a normal team could rally around is too much for one programmer to deal with (such as the much needed engine occlusion bug which broke a key avionics sub-system). Another mistake was getting pressured into announce a release period which was just setting myself up for disappointing people when problems arose. I broke my own rule and paid the price. While I still feel bad about that I love the team even though they probably hate some of the choices I made, I can't disagree. Will the release meet expectations? Probably not. Will it fly? You bet. Besides my wife said she'll cut off my bollocks if I don't release it soon or get a decent paying job. Can't argue with that either.

Video and film highlights of 2011

Everything is a Remix

If there was ever a documentary that shows how ridiculous, damaging and outdated modern day copyright and patent laws are, Everything is a Remix is an entertaining documentary series in 4 parts. Everything around us is a remix of some tool, idea and material. Without the freedom to copy, transform and combine existing ideas and technologies creativity is stifled and with it western economies. How different our world would be today if the same level of litigation was around at the time of the industrial revolution.

Sons of Guns - Discovery Channel

Once you get past the gratuitous 'gun porn' flag waving aspect what I love about this series is the sheer love and enthusiasm from the employees of Red Jacket Firearms featured in the show. Sure they love to blow stuff up and you might question the sanity and choices made (as do the employees from time to time) but the company is not run as a democracy (insert discussion here). Now airing the third season it's perhaps the most popular show on Discovery HD. It had me yelling, "I got a guitar GUN!" Cracks me up every time.

Cowboys and Aliens (imdb)

The film was better than the title. Reminding me a little of an old b-movie Valley of the Gwangi (imdb) it was a reasonably fun and gritty take on the what-if monster genre.

Super-8 (imdb)

A charming revisit of what an 80s Spielberg movie would be if made today....set in the 80s. Yes we wore those clothes in school. And if you have a 5.1 surround system then the train crash scene will terrify your neighbours. Written and Directed by J.J Abrams.

Cool science stuff

Energy from paper, discovery of hundreds of 'earth like' planets around nearby stars, the possible discovery of the Higgs Boson and Mentos in diet coke. Granted the last one is a bit late but is the only practical experiment I actually conducted in the kitchen. I did clean up though.

Here's hoping that next year science will bring us phones and portable computing devices that can keep a charge for more than a few hours.

Oh and the amazing new bulletproof liquid armor from BAE systems would be handy in the field. Currently it requires 10 pints of Newcastle Brown Ale to feel bulletproof and lightweight however field tests show the subject to be less than agile.

HAPPY NEW YEAR EVERYONE

(or I'll hit the UNDO button at midnight and we'll have to try all over again)

Parting quote:

"Goodbye. Goodbye to all the 87 software houses who are no longer with us . . . hello multinationals with your contract lawyers and your cut-price rotten little programs ..." - The Pi-man's end of the year message to fans circa mid 1980s

Source

## Bogged Down - Chin Up

I apologise for lack of updates, long time since the last one (weeks it seems although I have two unpublished ones which are no longer relevant). I've been avoiding online spaces during this time, work has been bogged down with the multitude of tasks not just relating to the Combat Helo game.

I'm working on the flight model again this week so don't expect any updates in a while. I did get started on an updated FAQ and will publish that ASAP. Lots of things happen around this time of year with concerts and church services, when you have a musical family there's a lot of evenings taken up with those.

So I don't know when we'll have something to show for all this work. It'll happen when it happens, there's no budget to finish and I've got huge debts that require me to stop at some point and take time off to do other work.

On the plus side I did get a nice pressie from one of my brothers which is going to buy a nice cheap car (sensible, used K car but importantly has a working HEATER, a nice to have feature for UK winters). Something to be said for being happy just by virtue of being in a car that's warm.

"Do you know what’s killing Western democracy, George? Greed, and constipation. Moral, political, aesthetic. The economic repression of the masses institutionalized." - Bill Haydon from John le Carré's Tinker Tailor Soldier Spy 1974.

Source

## Quick update - optimisations

Last week I identified one issue relating to UserEntityData introduced with the last engine update which prevents consistent update of Enity data due to some change in the hierarchy and no documentation on what was changed.

So I'm faced with having to re-factor (meaning to changing code but same behaviour) core sensor code. It's the sort of thing that is utterly frustrating and makes one want to throw everything out of the window. It's not as if there aren't enough things to do.

There's 4 major issues I'm not happy with:

• Flight Model bridge refinement
• Ground dynamics
• Horizon gapping and other asset problems (licences/legal, audio)
• Events / Triggers

I know I can rush some of these things and end up with something I'm not happy with. And if I'm not happy with it I don't see why anyone else will be happy. The majority of potential customers don't follow this blog, they don't care about how much work or team sizes, finds and lack-of, how or why, and often they don't care about the word "beta". To do what's right in the long term means having to not cut corners and do what needs to be done.

Sucks though.

Who would have thought building a stand-alone study sim of the most advanced attach helicopter on the planet would be so difficult? What gives?

Source

## Random pics of the Day

Some pics of the day.

Battlezoneesque - eerie (debug stuff)

Planning terminals awaiting attention

This is how I start every day

Source

## US Army showcases AB3 - Apache Block II to Block III in video

US Army released video showcasing the new Block III Apache in a virtual training environment.

The video covers in a nutshell...

• Weight reduction
• Increased engine power 701-D engines and improved drive system
• Better digital battlefield intergration
• UAV commanding
• IFR certified instruments
• Reliability and servicing improvements
• RFI range triangulation
• Maritime classification
• Awesome new logo

Source

## C-SCOPE

While Dave is away hopefully keeping his head above water (all those Bear Grylls survival videos should come in handy) I've got not much else to do except worry and get on with my to-do list.

C-SCOPE was something I remember saying wouldn't make it but turned out to be a freebie since everything was available to simply drop it in.

[C-SCP] button on the FCR page overlays FCR target symbols on TADS video and HMD. Makes finding those hard to see vehicles a piece of cake.

C-SCOPE FCR symbols presented on the HMD

The High Action Display is currently getting an update for the ACQ interaction (I've tried really hard to work through what this does and how I can gamify it to make something both usable and understandable by normal people).

Also I'm overjoyed at getting news of our ATC audio recordings and looking forward to playing with that.

Source

## Rain Stops Play - Bangkok Floods

Dave who is the artist on Combat-Helo is currently in the process of evacuating his home in Thailand as the floods in Bangkok have made living difficult. With no fresh drinking water for days, no supplies in the shops and place of work closed, services breaking down it's time to jump ship.

Blue indicates server flooding (clearly) Red=flood defence

BBC carries the story here

Dave's last act before evacuating was uploading the latest Chinook work to our server alas there was no time to upload the PSDs. Good luck and fingers crossed we'll hear from you in a week or a month...

Source

## Don't Panic

Yes Panic.

When you're rushing to get a reasonable build ready for hammering out problems I'm finding I'm making all new problems. Going over the HMD code I realise how badly it needs rebuilding, there are existing elements that need updating, a few new ones that require adding. There's no way to rebuild the HUD in time.

Another problem. LUA in the Apache entity. Works in the first instance, but fails in subsequent entity spawns resulting in the inability to mount the aircraft. It's an issue relating to LUA accessing keys stored in the model. I want to rip out all the LUA code from models except for the model initialisation that puts on pylons and attaches the rotor models. Not much time to deal with that either.

Dual Seat configuration.

The interaction between front and rear seat was not well thought out early enough, instead I opted for a 'duality' where all features could be operated from either seat with just some interface differences. I should have opted for a strict seat A can do xxxx and seat B can only do yyyy. This was a mistake in my attempt to simplify control but ended up introducing more complex logic.

It's not too late to undo this but a difficult process to start. If I have to design this game all over again I think I would probably nail down all of these problems from day one. Hindsight being wonderful.

TrippleHead - lot more pixels to post process, looks great but a GPU strain

Source

## Amazing what you can find on the internet today.

Not a Combat-Helo post. I'm engaged in a spot of design and research but was looking for some old material online and found I had left a digital trail pre-dating commercial internet use.

28 Years ago I drew this. I was in high school. Shocking really. I used Z80 machine code to generate the 'impressive' sound and visual effects in this game. *wince*

A lifetime of programming and tinkering, stacks of hard drives of unpublished projects ranging from Spanish school time-table generators to a Black Shark snapshot campaign generator.

Some material I doubt will ever be revived, the Memotech MTX 500 version of Next War was stored on cassette tape, probably oxidised beyond recovery. However the code lives on in other forms, the dynamic campaign system was enhanced and put to some use in a PC build. Some of which will form the backbone of the Combat-Helo campaign. One day I hope to merge the big war game with the Apache simulation and revisit the forgotten Fulda Gap scenario.

More unreleased WWIII fun and games

NATO vs Warsaw Pact at the Fulda Gap

Even my own attempt at producing a self-indulgent comic based on our exploits in the Star Wars Galaxies MMO...(PDF dug out of the old SONY Online game forums).

Even though the game will soon have the plug pulled the footprints we leave behind in the digital space will live on...for a bit.

I've rescued the original PDF and made it available here... Orion Outpost Chronicles part 4 - PDF

Anyway back to work.

Source

## Minigame...I mean gun

AD has started some great work on the armaments of the CH47 that will form the first major DLC pack for the full release of Combat-Helo. Each door position will offer a fun interactive activity, usually in the form of throwing out obscene amounts of virtual lead.

Mini-gun, I don't get the mini part though.

Source

## NTS Next To Shoot aka TAB targeting

[NTS] Left Upper button. Next To Shoot is the ubiquitous video game cycle through targets. Or TAB target if you play MMOs.

I've touched upon how radar works in this blog entry from August - Radar - A Discussion

The Apache can automatically selecting priority targets based on some sort of criteria. This short blog post touches on how I've elected to do this. Again if you're familiar with the 1996 classic, Janes Longbow 2 there's nothing unfamiliar here.

The TSD (tactical situation display) collects data from visual cues (look at object), radar and TADS (again look at and store). A linked-list of 3D entities is stored and sorted by range. The list is re-sorted by what type of object it is.

Target object sorting as follows:

• Fast Movers
• Helicopters
• Air Defence
• Armour
• Wheeled

Aircraft normally only show up in air targeting modes. The image above has one on the GTM Radar which is a BUG but that helicopter (another Apache) is on the ground.

Then these are sorted by range.

The [Cycle Target] key (default: TAB) steps through the list. This is different to the [Padlock Cycle] key (default: LCTRL F4) which applies to your head view and steps outward through visual targets sorted by range only. Sometimes the nearest isn't closest to the centre of view.

I'll touch on how I've programmed the game internally. A linked list of objects that are picked up in the FCR footprint are added to a TSDcontact list if the entity pointer (an entity is a vehicle) is not already present.

The game maintains separate lists from sensors and a Tactical(Situation Display) list which is used for referencing entities on the TSD. It also allows for messages received by the THelicopter message handler to add entities to the TSD when the player presses the 'ABCC download' button to download shared targets from a shared digital battlespace (fancy name for a simple array). To upload your TSD list you press the 'ABCC upload' function. I will think about expanding this to work on several channels in later versions.

Tactical Sensor Lists

The TSD used in our Apache vehicle is simply an instance of the TacticalSensor class which is used for all AI but the inputs are wired up differently.

These inputs are updated when in use, typically triggered by a player pushing keys. I've colour coded the inpus accoring to type. FCR is radar type area scan, high volume, Orange (HMD) is using the Mk1 eyeball, TADS in blue is an optical sensor (longer range eyeball) and Red is known data from external source, which you can imagine as a radio or some data modem.

As potentially there might be a hundred active AI vehicles in close proximity having all of these using all kinds of sensors, doing lots of volume searches and entity queries is woefully inefficient. Fortunately the natural hierarchical structure of unit can be simply used to make things much more efficient.

Since entities are grouped into Formations which share waypoints and mission targets, they share a common awareness. The same TacticalSensor class we use in our Apache. Only this time the inputs come from the different entities in the formation. Some will have an active sensor system, some are unable to supply input.

They periodically perform a sensor scan (interleaved to spread the load) to refresh their group TacticalSensor list.

Oh NO! The MIG! Target Priority

I'm sorting the linked list when updated based on criteria that I want based on experience from other games of this type. Worked for them, works for me.

In LB2 a Mig was triggered at random if flying over 250 ft. If not spotted quickly it was almost certain virtual death. To give these a high priority I added a Priority field to the SensorClass and arranged the icon IDs (1,2,3,4 etc) so by default the Priority value can be taken from the icon ID then modified later. Now the most dangerous entities can be simply sorted on this field but we could for example assign an entity as a "Primary Target" and add +10 to the Priority to have it automatically sit at the top of the TAB target list.

Very handy for scripting tutorials and the like. For example we can now spawn a virtual waypoint marker on a target range and command the avionics to give top priority.

So whatever the first entry on the linked list is, that's the NTS object, the second in the list would be the ANTS.

PFZs

Another often asked about feature in Combat-Helo is the ability to create PFZs. Which is something that only applies to the Hellfire missile system which is coming in a later update as we've not yet implemented it. However our Tactical list makes this a trivial matter to implement. We have a static list of entities, mouse input on the TSD map and mouse driven events. Everything needed to add PFZs and NFZs.

Correct weapon symbology coming soon

Whole HMD needs a going over.

Source

## Random Pics of the Day

Starting to feel the pressure now. Both the financial and stress factors are weighing in. Doesn't stop me working but it's hard to switch off. On the business side there's a ton of things on the to-do list, it all eats time taken from production.

Spooky, ok so the lip light isn't actually on his mic.

If it was you wouldn't see this.

Boeing sent me a poster back in 2002, this is a homage to that.

This time with the rear seat.

Taking out bad guys without damaging the good guys is a challenge.

Experimenting with simple TSD display and labels.

On top of this I'm studying some Unity material and shader programming. I could use a beer, a real one.

Source

## GROME 3.1 is out

Quadtree software has released the 3.1 update to Grome.

Grome is a fantastic terrain editor I've been playing with for future enhancements and rolling out a larger terrain systems in the future. If you play flying games and RPGs on consoles chances are you've probably already seen a Grome edited terrain. It's used by nearly every major player in the simulation industry. Incorporating a plug-in system, OpenSceneGraph and now new improved Unity integration.

What's new in 3.1

I'm quite keen to see how it works in the up and coming Leadwerks 3(D) engine which is looking to sport threaded streaming of assets. If this could be incorporated alongside the vegetation system it would be perhaps the most powerful and complete 3D engine for less than 1,000 USD.

Source

## Did I mention the FCR offset?

Remember the spinny radar thingy in Longbow 2? Scan sectors sizes and off-axis settings for the Longbow FCR (Fire Control Radar)? No?

If you look at the heading tape of the screen-shot you'll see in the heading tape the "butt-cheeks" (two Ds back to back) on a heading of 225, off axis by 45 degrees. This indicates the direction the radar is pointing, as the FCR display is 'always up' in GTM mode. This can be a little disorientating and the radar footprint is mirrored on the TSD, this paints a clearer picture of where it's pointing. Failing that you can see the radome outside the aircraft turning as it seeks out the designated offset.

(And why are all our aircraft IDs Z666? We shall never know. If you have a TrackIR and explore the cockpit nooks there's even a Clint Eastwood reference in it).

Radar offset angle is set by clicking on either of the two LEFT RIGHT arrow buttons on the MPD or your designated sensor left/right control input when the FCR is your selected sensor. (If TADS is selected the sensor control steers TADS instead). NOTE: The offset can not be moved while the FCR is active, although you can queue movement by hitting the offset control then quickly cycling the FCR burst key. Got it?

It will be in the manual. Promise.

Vectors - all vectors, no bitmaps

In the front seat, TEDAC view of the FCR

Source

## Apache Maintainers

On the topic of fuel systems, someone shared this video recorded at an FOB. One of the more difficult jobs.

Source