• entries
235
509
• views
172310

This journal has chronicled development progress on our released game titled 'Ancient Galaxy'.

## Finishing up AG Patch

I have made many changes since my last post, mostly in two areas, sound tracing, and NPC crystal usage.

The sound tracing is a system whereby I trace sounds from their source, through portals, towards the listener ( usually the player, but sometimes the camera ).

When the listener is in a different cell than the source, then the sound appears to come from the portal, rather than the actual sound source. The volume is also attenuated based on the linear distance from the source, to portal -> portal -> listener.

There were latent bugs in the sound tracing system that were only exposed when we expanded the 1st level of the game - issues where there were multiple paths from the source to the listener, each one of similar distance. There were some overly aggressive optimizations not to re-consider a cell already considered which were causing shorter sound paths to sometimes not be considered. This caused a sound to be heard when touching the portal, but not heard ( due to being culled ) when just outside the portal. Very distracting.

For a while I experimented with disabling the system, and just leaving the sounds at their true source positions, but since the sound tracing feature has been around so long, the levels sounded really bad without it.

I ended up making several fixes, each of which would solve another issue, which would expose another bug, some of which were recently introduced. Anyways, right now I believe the sound tracing system is close to bug-free.

Another small change I made was to make closed doors muffle sounds, in proportion to how closed they are. A nice effect when you are opening a door into an area.

There are many, many gotchas when doing a sound tracing system. Perhaps I will write them up one day.

The other change was pretty minor in terms of code, but seems to add proportionally more to the game is the ability of NPCs to use power-up crystals if they have one in inventory. They don't always use them, however, so the player can find some on NPC corpses.

At this point, we're just making some minor adjustments and fixing any remaining issues that come up, and then we will release the next version.

Every time we add a new level, it exposes latent bugs in the code that didn't show up in other levels.

We are adding another area to cavecity2 ( the last area of the shareware levels ), and in it is a winding ramp. Going down this ramp caused the camera to jump around in an unusual way that didn't happen anywhere else in the game.

Turned out it was the code added a few weeks ago to make sure the player wasn't obscured by something. In this case, the code just snaps the camera to a safe place near the player. It was getting triggered b/c going down the ramp, you tended to get your arms sort of through the wall while your physics capsule was in the right place. This caused enough of the raycasts to fail, triggering the safe area re-set.

Just outside the ramp were some black triangles only meant to obscure the mini-map, but that material was set to physically impede the camera, which was causing more issues. Fixing the material and also making the raycasts more bunched towards the capsule rather than the character's visual bounds fixed the issue.

The new AI code is working great - the Patrol state, which previously would get put off track rather easily, is working, and we added some debugging to give context when it fails.

I added a character speed adjustment to make the walk & run cycles more realistic. Now one of two sine waves are mixed into the movement speed of each character, making for a better looking and more rhythmic movement.

Then, I added a bit of camera up/down bob to match for the player, which is subtle but feels better.

## Implicit Dependencies...

As I'm wrapping up the 1.2 Ancient Galaxy patch, I think back on some of the challenges I've had with the AG Engine and why it can be somewhat of a cumbersome codebase to work with - similar to other complex software systems.

A largish piece of it is the fact that so many data and logic dependencies in the engine and game become implicit, and not articulated in any sort of manner that can be automatically checked ( like by the compiler, for instance ).

I been thinking one way to improve things would be to add explicit dependencies into the core of an engine, as a fundamental concept. A limited version of this would be ref-counting, where you at least prevent pulling an object away from another that's using it, although there are no guarantees w.r.t what state the object might be in.

Rather than ref-counting, which only tells you how many folks care about you, you might do reference linking, where you have a pointer back to the interested parties. With this you can create a rudimentary subscription ( or signal/slot ) model.

The next step would be to have an all-seeing, all-knowing subscription manager class that could manage subscriptions, something like this :

  struct Subscription  {	enum NotifyType	{ 	        ntNone			= 0x0, 	        ntRead			= 0x1,		ntWrite			= 0x2,		ntConnect		= 0x4,	        ntDisconnect     	= 0x8,		ntFrame			= 0x10,		ntPause			= 0x20,	        ntUnPause		= 0x40,		ntCreate		= 0x80,		ntDestroy		= 0x100,		ntUpdate		= 0x200,		ntSceneAdd		= 0x400,		ntSceneTraverse         = 0x800,		ntSceneRemove    	= 0x1000,		ntContact		= 0x2000,		ntTrace		        = 0x4000,	};	enum NotifyWhen	{		nwPre    = 0x0,		nwOn     = 0x1,		nwPost   = 0x2	};    uint32			_datum_id;    uint32                      _scope;    uint32                      _flags;    uint32			_subscribee;    std::vector< uint32	>       _subscribers;    // can hold history here, rather than in subscriber or subscribee    Datum::Value	        _history[ 16 ];    class Mgr    {        std::map< uint32, Subscription > _subscriptions;	public :        typedef void (__cdecl* Notify )( ( const Datum* const pDatum, const Subscription* pSubscription, const uint32& notify_type, const uint32& notify_when, const int32& datum_age );

One potentially interesting idea possibly beyond a standard signal/slots mechanism is the history, which can include the previous values of the data, for weapon trails, interpolation, etc. It could also be useful for futures and reading 1-frame behind data. You would subscribe to history -1 for the last frame, choose 0 for this frame, etc.

I also like the separation of the Pre/On/Post flags from the subscription type. That way any subscription type can be combined with the Pre/On/Post flags to allow you to hook in where you need to.

The scope value is there as a differentiator, for instance, an object may get added to multiple scenes, so you could have different scopes that would have separate subscriptions.

It seems this would allow things to be more data-driven, which can be good, but also places a larger burden on having tools to display & manipulate these dependencies...

## AI & Camera Tweaks

Made some more AI tweaks. The AI NPCs now will investigate a suspicious sound, and track the average location of various dangerous sounds they hear over time. This is known as the 'seeking' state.

This makes them gang up on the player, sometimes way too much, so I added a quota so that only so many guys can be seeking the player at one time - right now this is set to 4. Now, other NPCs can be attacking the player at once, but only 4 can be seeking him out.

Also, the enemies are more apt to detect the player's disguise when in Seeking state.

In addition, I added a little bit more camera physics. There was one case where the camera wasn't acting like a physical sphere, and it rarely caused the camera to move outside of the level.

The camera now acts like a ~1.5 meter radius sphere that tries to stay at an ideal user-tweakable player-relative position. It moves around physically, except if the player is completely hidden from view, in which case it 'cuts' right behind the player, then resumes it's physical sphere status. This is cut behavior very rare, but prevents much worse cases of the camera sphere getting stuck somewhere on the level and the player's character just wandering off.

## Sound Paths

Ran some in-game profiling over the past couple of days and found sound pathing tracing taking more time than I'd like.

Ancient Galaxy has a system to trace sounds from their source through portals into other cells, and then to the listener itself. This has the effect of making sounds appear to come through portals rather than a straight shot from the sound source if the listener is at least one room away from the sound.

It works really well most of the time, but can be a bit expensive to trace the sound paths from room to room every so often.

I was considering adding a precomputed data structure to speed this up. Basically the sound path goes

SoundSource->Portal->Through Cell->Portal->Through Cell->Portal->Listener

The paths are re-computed every so often, if the sound source moves or the sound is a looping sound.

I realized, though, that only the SoundSource->Portal and Portal->Listener parts need to be recomputed. The interior part, which could be 7-12 rooms longin some cases, doesn't need to be recomputed, and could actually be cached or completely precomputed. Each Cell or Portal could store its potentially connected portals, up the the limit of some level-specific sound distance cut-off. That way, only the ends of the sound path would by dynamic.

It turned out, though, that looped sounds were getting recomputed every frame, rather than only several times per second, so after fixing that, it doesn't look like I will need to speed things up any further in this regard.

In the future, I'd like to revisit this part of the engine and add environmental effects.

Also sped up the particle system, a couple of camera tweaks, and confirmed that the re-factored AI is still working well...

## Stately Progress

I'm happy to report that the re-factoring of the AI code is complete, and was a success!

Not only did I fix the main issues that I wanted to address, namely enemies and friendly NPCs occasionally getting stuck and/or lost, but the changes also fixed the Patrol state.

Patrol is where the designer has specified a # of triggers to walk to in some sort of order. A Patrol path can be linear or a cycle, and can have random elements as well. There was one level in particular when a group of Aakash lizard-men were supposed to follow the player, and they would usually get stuck or be so slow that the player only encountered the first couple of NPCs - now it works as expected, and that level is now much more exciting.

The basic shooting/hiding mechanism for combat works better too - the NPCs just move a lot more fluidly.

## State Lines

Over the last few days I have been re-factoring the AI code in Ancient Galaxy. It was written by another programmer, and was pretty good for the initial cut of it, but I didn't really take full ownership of it and re-think it later on, and now it's gotten out of control.

The original design had a Brain class, that contained a single current BrainState, which could be one of Waiting, Searching, Pathing, Wander, RePathing, Walking, Shooting, Hiding, etc.

This breaks down when you want the AI to be in more than one state at once, or remember what it was doing before, say Pathing. This was done in an ad-hoc manner of remembering a 'DestinationState' which was the state to do next. Part of the issue was that the DestinationState was what to do next if things went well. If you lost your target, couldn't make progress on your path, etc, it wasn't always clear what to do next.

I experimented with the idea of going for BehaviorTrees, which I have been using at work, but didn't want to implement a completely new system, and wanted the existing levels & save-games to work with any changes.

So, the current plan, which I have coded up, and am about to begin testing, is to have three concurrent states in the Brain class.

One Main State, which would be the AI's overall positioning & behavior strategy, like Flee, Wander, Follow, Patrol, None, etc.
One CombatState, which can be Shooting, Hiding ( for reloading, etc. ), Charging, None
One PathingState, which can be Pathing, RePathing, Searching or None.

The desired position-choosing logic used to be clustered in the Searching state, which used code like

if ( mDestinationState == "Charging" ) // choose a spot near the target

to choose a place with a good Line Of Fire, or a poor one ( for cover ), or near or far from the target, etc.

The new code uses virtual functions on the Brain states to get things like desired location bounding boxes, location evaluations, movement speeds, etc.

The Main State provides the bounding box of where to even look for navnode spots to go to. The Brain then chooses spots randomly inside the box. The Main State then gets to veto or evaluate these spots, then, if not vetoed, the Combat state can then chime in and veto or evaluate the remaining spots. Then the spot is selected randomly based on its desirability.

This way, the friendly NPCs can Follow the player, but still find Shooting and Hiding spots to attack enemy NPCs.

It feels great to rip out and simplify a bunch of code, but I'll let you know how it works out in game...

## Pulsing

This morning I made some fixes to the 'Slow Crystal', formerly known as the Pulse Crystal. This is an orange power up that lets you slow down the rate of fire, rate of reload, rate of shield regen of nearby enemies, and also shuts down their current shield.

I also made it slow down projectile speed as well, which is helpful for avoiding the rocket-like shots from the Higgs Pistol.

Also did some work on the new Blue Rescue crystal, which we are calling the Amplify Crystal, representing its new role in amplifying teleport signals.

Also made some minor level editor fixes, and adjusted the default camera setting.

In Ancient Galaxy, you have a spaceship that is used as a home base - a place to store, manufacture & analyze weapons & crystals, as well as a place to clone into an alien species.

We have been getting requests for the ability to go back to your spaceship without dying. Currently the only way to do this is to complete a level successfully and use a teleporter found in the level. Taken too far, the ability to go back on a whim has the potential to ruin the gameplay, but we see that it could be a good addition to the game if it is limited in some way.

One of the main changes that we will make is to change the way the Blue Rocks, Stones and Crystals work in order to provide this ability. The current behavior of the Blue Rescue crystal will be gone - that is, the ability to mark a location & return to it later upon death.

So, in the new version, your ship will gain the ability to pinpoint your location whenever you use a Blue Rock, Stone or Crystal. The ship's teleporter has difficulty locking on to a single lifeform next to a large planet filled with other lifeforms and a huge mass differential compared to your body, so the Blue crystal element acts as a focus for the ship's teleporter beam.

The crystal GUI will display the signal strength that the ship is experiencing in locating you, which is reduced by having other lifeforms or energy discharges nearby and being indoors or without a good view of the sky. Higher crystal strength ( Rock->Stone->Crystal ) will help the ship overcome this issue and beam you aboard with all of your equipment intact.

Your ship will require a recharge time so you cannot continually teleport back within a short timeframe.

If your signal strength is below 100%, there is a chance that the teleport will fail, and the ship will have to recharge to try again later, and your Blue Rock, Stone or Crystal is destroyed.

## Cameras & Boxes

Ok, managed to get the camera paths improved. I was using a simple method of interpolating the camera keyframes, but it failed when I made too few keyframes.

Basically, I made 3 points, one for location, one for location + facing, or for location + up vector, for each keyframe, then did Catmull-Rom interpolation on each point to regenerate the camera position & orientation. It worked well for my older camera paths, but the new ones I just made didn't work great, so I switched to Quaternion interpolation of rotation, and use the Catmull-Rom as before for position.

I've been working on a new spatial hierarchy - man, I've written so many of these, both for use in Ancient Galaxy, and other projects. Ancient Galaxy uses a BVH for world tiles, each of which contains a per-material AABB triangle tree. Dynamic objects also live inside BVH trees. To move objects, I delete them from the BVH, then re-insert. No rebalancing happens during these steps, that is instead done per-frame.

The new hierarchy I've been developing is something I call a BoxTree. It is a binary tree of AABox Nodes, each of which can have zero or two children. Nodes with zero children can have up to 8 Items in them, each with a AABox from the user, and a void* user data pointer. Items do not live higher in the tree than the leaf nodes.

Each non-leaf node also stores an Axis value ( 0,1 or 2 representing x,y or z ), a Partition value, which is a float that measures along this axis, and the UserData pointer last used to partition the node.

In some ways it is like a KD tree in the sense that you are sort of storing a split plane, but in other ways it is a balanced binary tree in the sense that when you are splitting nodes with 8 items, you do a median split, so that 4 items always go down the left child and 4 go down the right.

One bug with it I fixed today was with the case where 2 items were exactly on the partition value ( the axis-aligned split plane ), with one being the 4th item and the other the 5th. These two items would go down the left & right sides respectively, but later on when searching for one of these items, I didn't want to have to search both left & right subtrees.

The solution was to also store the last user data pointer used in the partition. This way, an item always goes down a particular way, left or right, never both, because you can use the user data pointer to break ties when the partition values are the same. This pointer only has to be remembered when a split happens - it doesn't even need to be changed if that item gets deleted, the pointer value itself is the tiebreaker, so it remains valid even if it doesn't point to anything.

With that change, my unit tests are passing despite adding & removing several hundred boxes at random.

Just realized that the tree doesn't handle duplicate items nicely - if you add > 1 item with the same userdata pointer, you will find one of them, but maybe not the one you expected. I suppose I will add two new methods, one that adds an item but checks for dupes and replaces the dupe with the new value and another one that fails on adding a dupe.

Next is to test the cases where I have many duplicate boxes, and ensure the splitting logic is robust.

## Camera Shots

Based on comments to this blog, and from one of our testers, I added some camera paths to the 1st level of the game.

Camera paths are one of the features I added to the game quite a while ago, but never really exploited as much as I could have.

Camera paths are non-interactive sequences where you lose control of your character, and the camera follows a specific path through the scene, set via keyframes. Pretty standard for many games, and especially good for games where pressing a button in one spot can open a door elsewhere.

The interface for creating cameras in the editor is pretty good - you just move the level camera where ever you want, then hit 'New Camera', and it will create a camera to mirror the current camera position & orientation. You can then add a 'cam_path' string to the camera keyframe that puts it on a certain path - all camera keyframe with the same string are combined into a path - and also a float called 'cam_path_time' that is used to sort the camera keyframes in order. You can also add a 'cam_pause' time that is used to pause the camera once it reaches a keyframe.

You can also select a camera then force the level editor camera to match it, but I need to add a way to re-fit a selected camera to the level editor camera after creating it.

So, I added a camera path at the very beginning to show you where to scan your 1st symbol, then I added a camera to show you the skull key, then I added two camera paths to show that the buttons raise the gates near the end of the level. I may add another to show off the ship hangar doors opening as well.

As I go through the game for more testing & tweaking in anticipation of a patch, I will look for other places to place camera paths as well.

I remember playing Blade of Darkness - great game btw, that would do a camera path through the level, not enough to give pieces of the level away, but just enough to give you a mood for the place, along with good music and a nice voice-over going through the history of the place.

## Noisy

After diving into the camera code to fix the fps-independence issue, I remembered something I heard from a director on a popular animated CG movie. He suggested adding noise to the camera movement. He also suggested that doing some tricks that make it look like a real cameraman is working is even better.

However, just adding 4 octave noise to the desired camera position is enough to add a bit of life to an otherwise static camera angle, without being distracting.

I'm also getting more interested in 3d stereo and may try to make AG play nice with 3d stereo - haven't tried it yet, although I have a 61" 3D ready Samsung DLP TV that is begging for me to try AG on it!

In other news, we have had some sales of Ancient Galaxy, but haven't received much feedback other than the sales themselves.

I'm curious if there is any feedback from those who have tried it so far...?

## Camera Smoothness & AABB Culling

After checking out a preliminary promotional video, I noticed that the camera looked very stiff and unnatural, although I have camera smoothing code in the game.

After looking at the code, I realized it was probably the fact that the camera smoothing was not fps-independent and the recording was reducing the framerate, so I fixed the camera interpolation code to be shorter, simpler, faster and also fps-independent.

The other day I was revisiting AABB frustum culling for another purpose, and realized that in Ancient Galaxy, I was doing too much work in the frustum culling code.

There is a trick for AABB vs plane testing, in 2D ( as used in the Larrabee rasterizer ), and also in 3D ( used for frustum culling and BSP traversal ), where you take advantage of the axis-alignment of the box to only test a single point of the box to find out if the box is fully in back of the plane. You can also test the opposite point to find out if the box is fully in front of the plane.

Anyways, I saw that my code was always computing both points, to try to distinguish the Outside from Inside and Partial cases, although the code using this function was only checking for Outside or not. So, I made a new function that only does the Outside check.

It's possible doing & using the Inside check can speed up tests b/c once you are fully inside a plane, any children in a hierarchical tree won't have to be re-tested against that plane.

Here is the code for future reference :

bool Shapes::Frustum::Culled( const Shapes::AABox& aBox ) const{    // for each plane of the frustum    for ( size_t p = 0; p < Shapes::SidesCount; ++p )    {	D3DXVECTOR3 furthestPoint( aBox.Min );        if ( mPlanes[ p ].mNormal.x >= 0.0f ) { furthestPoint.x = aBox.Max.x; }         if ( mPlanes[ p ].mNormal.y >= 0.0f ) { furthestPoint.y = aBox.Max.y; }         if ( mPlanes[ p ].mNormal.z >= 0.0f ) { furthestPoint.z = aBox.Max.z; }         if ( mPlanes[ p ].GetClipStatus( furthestPoint ) == Outside )        {            return true;        }    }    return false;}

The idea is that if the furthest point on the box in the direction of the normal is behind the plane, then all closer points must be behind the plane as well. Sort of reminds me of the Separating Axis Test.

## Wrapping it up

Over the past few months I have been making small fixes to the game, but also doing a lot of release-related work. What is that, you ask? Well for those developers who haven't been through the process, I'll elaborate :

1) Made a fully automated asset build system. One batch file packs up all the relevant assets ( and skips unused assets ), gets the latest exe & dlls, signs the exe, applies the license mgr to the exe, then runs the installer, then signs the resulting installer exe.

2) Made a new asset packing system. Was using Molebox ( great program, btw ) to pack up the assets, dlls & exe into one large exe. Worked well until I tried to pack up the game afterwards with SoftwarePassport - so I had to leave some assets unpacked, and make my own pak format for dds, x, csv and text files.

3) Improved & fixed the installer, using NSIS Installer, great, scriptable and free.

4) Changed the game from shareware/registered exe versions to a single unlockable exe.

## Ancient Galaxy Released!

I'm proud to announce that Ancient Galaxy has been released. You can download a 3 level version here :

If you enjoy it, or just want to support independent game developers, you can register it and receive a code to unlock the other 20 levels here :

The game was developed with the help of some folks I met here on GameDev.net, and much of its active development was covered here in my dev journal.

Now that the game is out there, I will have more time to update the dev journal, probably focusing on some of the issues we have had wrapping the game up and getting it shipped.

## Thievery

The other night as I was making fixes and running through one of the levels, I had trouble finding a certain key needed to enable the teleporter controls, allowing me to leave the level.

I was a bat clone, and was successfully sneaking through the level without being detected by keeping away from other bats as much as possible, and hadn't killed anybody so far in the level.

When I dumped out the entity information to a text file, I combed through it an realized that the cultist Inspector had the key I needed, and since I hadn't killed him, I didn't get it.

It struck me as rather lame that you couldn't do stealth to complete the level, so I added another Teleporter key to another level section.

Then I thought about it some more, took out the key, and added a fun wrinkle to the game. Now when you sneak by a friendly NPC that hasn't detected you, any key he is carrying shows up as a takeable item, and you can grab it! When you do this, his detection level of you goes up quite a bit, but if he is completely unaware of you, you can still sneak by him successfully.

Tried it out, and it was definitely fun. The enemies detect you much more readily when you are up close, so it's a bit nerve wracking to walk by and try to snag his key.

I thought about allowing you to grab weapons, too, but a) I think it would get too cluttered on the screen, and b) it would be hard to choose whether you wanted a key or weapon as he's walking by, and c) they would definitely notice if you took their gun!

Anyway, fun times.

As far as Ageia support, that was removed a while ago, I'm back to my custom physics engine, although if I were to use one today, I think Bullet would get the nod, due to the CCD and the fact that it's free...

Today I adjusted the Slave Warrens level, and need to fix up the ending level tonight a bit.

## This just in...

Ancient Galaxy is fun.

After spending so long fixing & tweaking, it's easy to lose sight of the fun factor after a while, but I just played through the shareware levels, and I thoroughly enjoyed myself.

Some of the things that make it fun after playing it in one form or another for so long -

1) stable - no crashes or strange behavior.
2) only a couple of bugs that I noted to fix later. nothing major.
3) much better sounds - i added custom doppler & random pitch shifts which adds a lot of variety. also fixed the torch sounds this morning.
4) fixed a bug where NPC item lists weren't as random as advertised. This opened up the weapon mix for & against my char - much more enjoyable and varied
5) fixed a weapon damage per second display issue
6) better ai after several weeks of one or two small fixes and tweaks a week

I started as the main bald character - the only one to be available in the shareware version. I completed the digsite level without too much trouble, although this time Nejeb ( friendly npc ) died before the end, which is unusual.

The cavecity1 level was much more challenging once I aroused a bunch of Aakash lizard men. The 'boss' guy was dual wielding gauss pistols and took me down twice, despite me using a green power crysal to do more damage to him. Then I remembered that I had enough DNA to become an Aakash, so I did so and went to the 2nd part of cavecity, where I tousled with some Thoog bull creatures, which killed me once.

In between levels, I raised my skill levels in shield, cloning & weapons, and manufactured some more weapons as I needed them after death.

The bat creaturess at the end of cavecity1 had me completely pinned down with some area of effect weapons for over a minute, so I charged them, got one down while another was reloading, was able to take the bat's weapon, then retreat and get healed a bit before killing the 2nd guy. Next I heard the bats & lizards fighting one another, so I ran down and mopped up, including the 'boss' aakash I had snuck by earlier as a cloned Aakash!

Very fun.

## Up and running again

Ok, we are both up & running again with our pcs. I ended up getting my old pc back up without one of the two striped harddrives.

All I ended up losing were some pictures, and a couple of mp3s, not a huge deal.

We now have all of the levels lit properly using an ambient cubemap. I used to have separate ambient render passes for with and without ambient cubemaps, but I standardized on requiring one to be specified, or a default gray cubemap will be used.

The indoor levels made the biggest visual improvement with the ambient cubemaps, although most of them didn't have one specified before.

Another big change was to move from SDL_mixer audio to the IrrKlang library. I used fmod ages ago, didn't want to pay the high registration fee, so tried sdl_mixer, had stuttering issues on and off, so I switched to IrrKlang, and now that everything is running with the new system, I'm happy with it.

I had an abstraction layer for sound, which worked well enough in between fmod & sdl_mixer, but it needed some tweaks for irrklang. Also, irrklang didn't support fading in & out of sounds ( which I used for music ), so I had to add that for the music part. I think you probably need at least 3 libraries behind your abstraction layer before it stops needing tweaks for new back-ends.

I did have trouble getting irrKlang to play back 3d audio ( using software 3d buffers ) at the right volume & positions that I wanted, so this morning I changed the code to always give sound positions to irrklang in a 4 meter circle around the listener, and just scale volume myself by my own function.

Currently I'm using vol = sqrtf( 1.0f - dist / max_dist ), and it works well for me. The sqrt is there to make sound fall of less than linearly and pull far sounds a little closer to the listener.

I also made some small improvements to the sound path tracing code that traces sounds from cell to cell through portals, trying to find the listener.

We are now considering making a gallery mini-level to show off some of the content in the registered version to shareware customers, although we may stick with screenshots. We are also considering a gallery for the various clone types available rather than the text menu we have now.

Lastly, we are looking at ways of differentiating the 4 character choices at the start of the game via unique abilities or powers.

## Interesting Times....

Within the same 12 hour period, both my partner and I, in separate time zones, had our main hard drives die. What are the chances?

Needless to say, we got a lesson in how to get things up & running again quickly. Luckily, most of the project was on an off-site subversion server, so the main code was easy enough to bring up again, although there were a few config files we didn't check in to avoid stepping over each other - now we have backup defaults checked in to prevent having reconstruct them in the future.

The week before I spent wresting with compiler issues, I found out that the _SECURE_SCL=1 setting ( on by deafult in all configs for vs2k5 and later ) will gladly link code with libs that have _SECURE_SCL=0, and thus generate no end of runtime errors for your pleasure. The sheer joy of rebuilding all of my libraries with the same setting was intense for sure, not to mention the days it took to diagnose the issue in the first place.

The only solace, is that I have improved the ambient lighting in the game mightily, via a series of hacks which I will describe once I can get the game running again on this machine, instead of my deathly slow vista box.

Another upside, I suppose, is the tools & techniques I have learned in the process, and the cleaning up of unnecessary dependencies, code and data files.

Hopefully we will be back to full speed at the end of the week, and can put together the release candidate.

## Fragmented

OK, we figured out a good way to improve the usefulness of crystals in the game. To explain why we needed to change it, I should give some background facts about the game as a whole and the previous system.

Possibly the main Unique Selling Point of our game is that you can scan corpses of alien DNA, and that, given you've captured enough DNA to sequence their genome, you then clone the alien race, and 'become' an alien. This is something that you can do on your ship, which acts as the meta-game area in between missions, where you can re-equip, perform cloning, upgrade skills, make weapons, etc.

Because of this, we have taken out saving & loading the game. If your corpse dies on a level, the level is saved with your corpse, and you are re-cloned as the last chosen type by your ship, and you start back on the ship. Some things stay on your corpse, like any weapons, crystals, scanned DNA, and scanned crystal elements, for you to retrieve by scanning your corpse later.

Cloning can help you complete a level in a couple of ways - one is that you can use the alien clone body as a disguise that will protect you from attack for a certain time when confronted by aliens friendly to your clone body type. Another is that each alien clone type has a power that they can use pretty much once per level that is fairly powerful, and may really help in a particular situation.

DNA is not used up by cloning, so you can use cloning to get 'unstuck' if you have a tough challenge in a certain level.

But, crystal elements on your corpse remain there after death until scanned, so if you want to rely on crystals, you can't if you die part way through a level.

So, we changed it so the weakest type of crystal is makeable once you have enough skill and have scanned its constituent elements at least once. This way you can use crystals even if you have no crystal elements in inventory, although the more powerful versions of a crystal still require elements to create.

## hmmmmm

Some more improvements :

- Fixed gunfire kick to be cumulative
- Made kick divided by burst count for burst weapons to make tuning easier
- Made submachine guns suck a bit less
- Made explosions for traps more powerful
- Worked on info displays for clones
- More fixes to corpse sliding
- Made shield distortion use weapon hit color
- Fixed crystal shape display issue in gui
- Made rock->stone->crystal have a more even visual progression

The game contains some interesting weapons - one of which is a trap gun that shoots a special projectile that arcs through the air & sticks when it lands. It then sets up an explosion radius around it. If a creature comes within the radius, it explodes. I recently added the fake light effect to it to show the radius more clearly.

The problem was that the area effect / splash damage distance was the same as the radius, so when someone set it off, that meant they were getting like 1% damage, b/c they were near the edge, so I changed it so the area effect scaling is stronger than the effect radius.

Also discussing how to make the crystals more useful.

## Update

Long time no update.

We are in late beta test right now with Ancient Galaxy.

Here are some highlights of the changes since the last update :

- Distortion shader effect for explosions & laser blasts
- Numerous AI fixes
- Fix to air control to keep player from getting where he shouldn't
- Bullet casings from bullet weapons
- Fake point light effect for aiming reticles
- Fake point light effect used to make flareguns & flashlights
- Items like flareguns, flashlights, tractor guns, forcefield guns moved to Equipment status instead of weapons
- Equipment can be created always once found
- Fixed character scaling code
- Added a small amount of random scale variation
- Many many level improvements
- Redesigned main UI menu and some others
- Game saves AA & Quality settings from last run
- Recolored in-game menus to nice blue/yellow scheme
- Added text object export from editor
- AI can now use gravity-ammo weapons OK
- DPS calculation fixed to properly account for area effect
- Fake lighting added to area traps to represent trap area
- Distortion added to shield effect
- Added level preview screenshots for each level
- Fixed knockback on damage
- Made corpses slide for a while before settling still
- Made hints not pause game, or require [space] to dismiss

Recently we also changed the shooting mechanic from random jitter to a upward kick when shooting mechanic, with a little random jitter.

A couple weeks ago I vastly reduced the lightmap space taken by the game by switching the main light to A8L8 from A8R8G8B8, and sometimes to L8 if the level has no sunlight. Also made empty worldtiles use 2x2 black texture.

The flashlight was a fun thing to add. It is sort of a hack but works very well in practice. Basically I do a ray cast from the player muzzle pos outward, then draw a fake point light where the ray hits something solid, scaling up the fake spherical point light, and adjusting the brightness based on the distance from the player and the radial size of the flashlight's effect.

## Smarts

We are still tweaking & tuning the game, trying hard to release soon. We already submitted for IGF, but since they accept updates, we're hoping a new version improves our chances.

Some changes since our last update :

The player's gun always displays an aiming reticle, even when there is not a laser sight on the weapon

The AI will notice if the player has not taken damage for the last two shooting state cycles, and will try to move closer to the player.

The AI realizes when its accuracy is dropping low, and holds fire until the accuracy gets > 30% of their nominal accuracy with the weapon.

The AI will reload if it doesn't have LOS to the player for a while and has < 50% bullets in the clip.

If the reloading will taking a while, then the AI will switch from shooting to cover mode early.

The AI now uses its true muzzle positions to detect shootability to the player, and the player's real muzzle positions for his shootability, reducing times when the AI thought it had cover but was being shot, and where it thought it didn't have a shot, when it actually did.

A bunch of the AI fixes were enabled by the new 'Ephemeral' data structure. Previously, almost all new entity data was added via facets, which are a accessed via a string->variant map attached to each entity. Facets are automatically saved & loaded, and aren't part of the static footprint of the entity class, so don't break saved games or cause long compiles if added directly to Entity.h.

But increasingly, things that were accessed every frame were put in facets, and they didn't need to be tweaked via the facet system, so didn't need to be in there at all, so I made an struct called Ephemeral which holds temporary data that is not saved or loaded with a saved game.

The ephemeral struct is forward declared in entity.h, so only a small fraction of files have to be recompiled when it changes, and since it doesn't save or load, it doesn't break levels or saved games.

It has about 40 members now, most representing things moved from facet->ephemeral, but others just added partly because it's way easier to code directly on a struct rather than through the facet system.

Some examples of things in the ephemeral struct are animation blending coefficients, LOD values, current light occlusion values, whether the AI should reload, the player's tension value that controls the music changes, values for which walk sound to play, water sound fading, the current muzzle locations of each gun in an entity's hand, etc.

An arch change that would have allowed both styles of coding on the same data might be one where there were two structs in an entity, the persistent data and the ephemeral data. Data would be accessed either via the struct directly or via a string->struct offset lookup. The permanent struct would be saved, and the other one not, but it could be reloaded from facets to initialize it at loading time.

So, while I highly recommend a property/facet system, be careful over-using it, and pull common things back into code, which gave me quite a nice speedup.

## It's Done...

Well, finally the game is what could be called a late release candidate. There are some things to work out with the installer, and a few help menus that would be nice to add, and perhaps a bit of text and balance tuning, but the game is basically done.

It's been incredibly challenging to get it to this point. The game was overly ambitious for the size of team we ended up with ( 2 ), but now hopefully we get to the rewarding part.

We submitted the game to the Independent Games Festival, and hope to do well there. I imagine we have submitted one of the larger and more ambitious games, so, hopefully that works on our favor. We are out to prove that Indie != Casual.

The last few weeks have been spent bug fixing, polishing, balancing, and doing really fun things like making sure the game runs under Guest user mode on XP & Vista ( it does ), and figuring out the DirectX setup thing.

I added a NPC Follow AI mode, where a npc will follow the character pretty closely, usually without getting in the way, and will fight for you or against you depending on if he's friendly or not.

Also a bunch of more script trigger events, such as the end of a speech, the death of a character, the dismissal of a hint screen, all of which were key to advancing various plot points.

The final game ended up being ~14 levels in size. Our plan is for the shareware version to encompass 5 levels worth, which should be enough for people to get a feel for it and try out the cloning feature.

Readers of this forum are encouraged to contact me if they would like to be game tuning beta testers over the next week or two.