Code Cleanup: AI
After the 'high profile' enhanced Pyro coding had been going on during the last few weeks, I have found some time now to do some direly needed 'behind the scenes' clean up and reworking of the existing code base, which still in parts is a big, ugly mess, stuffing dozens and dozens of functions with thousands of code lines into one or two completely unstructured source files. I tried to avoid this task, but having to deal with bugs and flaws in exactly that code forced me into bringing it into a shape I could work with.
What I had tackled first was the AI code. I ended up in splitting two huge files into ten smaller ones that actually
contained what the file names suggested. The main AI dispatcher function was a moloch with over 1000 lines of code, performing several tasks
all in one. Well ... it worked somehow, so the guy who wrote it shall be forgiven - at least he is one of the guys who brought us Descent. 
I moved each AI function's code block into a separate function that gets called via a function table using the AI state as table index. Instead of juggling around with a bunch of separate data areas, the communication between the various functions is performed by exchanging a neat and clean data block. Here is an excerpt of the code as it looks now to give you an impression (before, each function call was a big block of code):
void DoAIFrame (tObject *objP)
{
tAIStateInfo si;
// initialize si here
si.nObject = OBJ_IDX (objP);
si.nObjRef = si.nObject ^ gameData.app.nFrameCount;
...
if (AIFireHandler (objP, &si)) return;
if (AIApproachHandler (objP, &si)) return;
if (AIRetryHandler (objP, &si)) return;
if (AIMatCenHandler (objP, &si)) return;
if (AIAwarenessHandler (objP, &si)) return;
if (AIPlayerDeadHandler (objP, &si)) return;
if (AIBumpHandler (objP, &si)) return;
...
}
Here is an example of using a function table instead of a big list of separate state queries (before, there was a huge case statement instead of the function call via the table):
// type of the handler function
typedef int (* pAIHandler) (tObject *objP, tAIStateInfo *);
//the function table containing the handler functions for each state
static pAIHandler aisHandler1 [] = {
AISNoneHandler1, AISRestHandler1, AISSearchHandler1,
AISLockHandler1, AINothingHandler, AISFireHandler1,
AISRecoverHandler1, AINothingHandler};
int AIForceFireHandler (tObject *objP, tAIStateInfo *siP)
{
tAIStatic *aiP = siP->aiP;
...
//only call function if the state points into the table
if ((ushort) aiP->CURRENT_STATE < AIS_ERROR)
return aisHandler1 [aiP->CURRENT_STATE] (objP, siP);
return AISDefaultHandler1 (objP, siP);
}