/*
	This file is part of Warzone 2100.
	Copyright (C) 1999-2004  Eidos Interactive
	Copyright (C) 2005-2007  Warzone Resurrection Project

	Warzone 2100 is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	Warzone 2100 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Warzone 2100; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
 * Function.c
 *
 * Store function stats for the Structures etc.
 *
 */
#include <stdio.h>

#include "lib/framework/frame.h"
#include "function.h"
#include "stats.h"
#include "structure.h"
#include "text.h"
#include "research.h"
#include "droid.h"
#include "group.h"


#include "multiplay.h"


//holder for all functions
FUNCTION	**asFunctions;
UDWORD		numFunctions;

//lists the current Upgrade level that can be applied to a structure through research
//FUNCTION_UPGRADE		*apProductionUpgrades[MAX_PLAYERS];
//UDWORD					numProductionUpgrades;
//FUNCTION_UPGRADE		*apResearchUpgrades[MAX_PLAYERS];
//UDWORD					numResearchUpgrades;
//FUNCTION_UPGRADE		*apArmourUpgrades[MAX_PLAYERS];
//UDWORD					numArmourUpgrades;
//FUNCTION_UPGRADE		*apBodyUpgrades[MAX_PLAYERS];
//UDWORD					numBodyUpgrades;
//FUNCTION_UPGRADE		*apRepairUpgrades[MAX_PLAYERS];
//UDWORD					numRepairUpgrades;
//FUNCTION_UPGRADE		*apResistanceUpgrades[MAX_PLAYERS];
//UDWORD					numResistanceUpgrades;
//FUNCTION_UPGRADE		*apWeaponUpgrades[MAX_PLAYERS];
//UDWORD					numWeaponUpgrades;

/*Returns the Function type based on the string - used for reading in data */
static UDWORD functionType(char* pType);
static BOOL storeName(FUNCTION* pFunction, STRING* pNameToStore);
static BOOL loadUpgradeFunction(char *pData, UBYTE type);


//array of functions pointers for each load function
BOOL (*pLoadFunction[NUMFUNCTIONS])(char *pData) =
{
	loadProduction,
	loadProductionUpgradeFunction,
	loadResearchFunction,
	loadResearchUpgradeFunction,
	loadPowerGenFunction,
	loadResourceFunction,
	loadRepairDroidFunction,
	loadWeaponUpgradeFunction,
	loadWallFunction,
	loadStructureUpgradeFunction,
	loadWallDefenceUpgradeFunction,
	loadPowerUpgradeFunction,
	loadRepairUpgradeFunction,
	loadDroidRepairUpgradeFunction,
	loadDroidECMUpgradeFunction,
	loadDroidBodyUpgradeFunction,
	loadDroidSensorUpgradeFunction,
	loadDroidConstUpgradeFunction,
	loadReArmFunction,
	loadReArmUpgradeFunction,
	//loadDefensiveStructFunction,
	//loadRadarMapFunction,
	//loadPowerRegFunction,
	//loadPowerRelayFunction,
	//loadArmourUpgradeFunction,
	//loadRepairUpgradeFunction,
	//loadResistanceUpgradeFunction,
//	loadFunction,
//	loadFunction,
//	loadFunction,
	//loadBodyUpgradeFunction,
	//loadHQFunction,
};

BOOL loadFunctionStats(char *pFunctionData, UDWORD bufferSize)
{
	char		*pStartFunctionData;
	UDWORD		totalFunctions = 0, i, type;//, player;
	STRING		FunctionType[MAX_NAME_SIZE];
	FUNCTION	**pStartList;

	//keep the start so we release it at the end
	pStartFunctionData = pFunctionData;

	totalFunctions = numCR(pFunctionData, bufferSize);

	//allocate storage for the Function pointer array
	asFunctions = (FUNCTION**) MALLOC(totalFunctions*sizeof(FUNCTION*));
	if (!asFunctions)
	{
		debug( LOG_ERROR, "Out of memory" );
		abort();
		return FALSE;
	}
	pStartList = asFunctions;
	//initialise the storage
	memset(asFunctions, 0, totalFunctions*sizeof(FUNCTION*));
	numFunctions = 0;
	//numProductionUpgrades =	numResearchUpgrades = 0;//numArmourUpgrades =
		//numRepairUpgrades = numResistanceUpgrades = numBodyUpgrades =
		//numWeaponUpgrades = 0;

	for (i=0; i < totalFunctions; i++)
	{
		//read the data into the storage - the data is delimeted using comma's
		FunctionType[0] = '\0';
		sscanf(pFunctionData, "%[^',']", FunctionType);
		type = functionType(FunctionType);
		pFunctionData += (strlen(FunctionType)+1);

		if (!(pLoadFunction[type](pFunctionData)))
		{
			return FALSE;
		}
		//increment the pointer to the start of the next record
		pFunctionData = strchr(pFunctionData,'\n') + 1;
	}
	//set the function list pointer to the start
	asFunctions = pStartList;

//	FREE (pStartFunctionData);

	//create Upgrade arrays
	//for (player = 0; player < MAX_PLAYERS; player++)
	//{
		/*apProductionUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numProductionUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apProductionUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}

		apResearchUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numResearchUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apResearchUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/

		/*apBodyUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numBodyUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apBodyUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/

		/*apArmourUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numArmourUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apArmourUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/

		/*apRepairUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numRepairUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apRepairUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/

		/*apResistanceUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numResistanceUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apResistanceUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/
		/*apWeaponUpgrades[player] = (FUNCTION_UPGRADE *) MALLOC(numWeaponUpgrades *
			sizeof(FUNCTION_UPGRADE));
		if (!apWeaponUpgrades[player])
		{
			DBERROR(("Out of memory"));
			return FALSE;
		}*/
	//}

	//pStartList = asFunctions;
	//numProductionUpgrades =	numResearchUpgrades = 0;//numArmourUpgrades =
		//numRepairUpgrades = numResistanceUpgrades = numBodyUpgrades =
		//numWeaponUpgrades = 0;
	//now fill the Upgrade arrays
	//for (i = 0; i < numFunctions; i++)
	//{
	//	switch ((*pStartList)->type)
	//	{
			/*case (PRODUCTION_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apProductionUpgrades[player][numProductionUpgrades].functionInc = i;
					apProductionUpgrades[player][numProductionUpgrades].available = FALSE;
				}
				numProductionUpgrades++;
				break;
			}*/
			/*case (RESEARCH_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apResearchUpgrades[player][numResearchUpgrades].functionInc = i;
					apResearchUpgrades[player][numResearchUpgrades].available = FALSE;
				}
				numResearchUpgrades++;
				break;
			}*/
			/*case (ARMOUR_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apArmourUpgrades[player][numArmourUpgrades].functionInc = i;
					apArmourUpgrades[player][numArmourUpgrades].available = FALSE;
				}
				numArmourUpgrades++;
				break;
			}*/
			/*case (BODY_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apBodyUpgrades[player][numBodyUpgrades].functionInc = i;
					apBodyUpgrades[player][numBodyUpgrades].available = FALSE;
				}
				numBodyUpgrades++;
				break;
			}*/
			/*case (REPAIR_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apRepairUpgrades[player][numRepairUpgrades].functionInc = i;
					apRepairUpgrades[player][numRepairUpgrades].available = FALSE;
				}
				numRepairUpgrades++;
				break;
			}*/
			/*case (RESISTANCE_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apResistanceUpgrades[player][numResistanceUpgrades].functionInc = i;
					apResistanceUpgrades[player][numResistanceUpgrades].available = FALSE;
				}
				numResistanceUpgrades++;
				break;
			}*/
			/*case (WEAPON_UPGRADE_TYPE):
			{
				for (player = 0; player < MAX_PLAYERS; player++)
				{
					apWeaponUpgrades[player][numWeaponUpgrades].functionInc = i;
					apWeaponUpgrades[player][numWeaponUpgrades].available = FALSE;
				}
				numWeaponUpgrades++;
				break;
			}*/
			//default:
				//do nothing
	//	}//end of switch
	//	pStartList++;
	//}
	return TRUE;
}

// Allocate storage for the name
BOOL storeName(FUNCTION* pFunction, STRING* pNameToStore)
{
#ifdef HASH_NAMES
	pFunction->NameHash=HashString(pNameToStore);
#else
	pFunction->pName = (STRING *)MALLOC(strlen(pNameToStore)+1);
	if (pFunction->pName == NULL)
	{
		debug( LOG_ERROR, "Function Name - Out of memory" );
		abort();
		return FALSE;
	}
	strcpy(pFunction->pName,pNameToStore);
#endif
	return TRUE;
}

/*BOOL loadFunction(char *pData, UDWORD functionType)
{
	FUNCTION*				psFunction;
	STRING					functionName[50];

	//allocate storage
	psFunction = (FUNCTION *)MALLOC(sizeof(FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION*)psFunction;
	numFunctions++;
	asFunctions++;

	//set the type of function
	switch (functionType)
	{
	case DROID_DESIGN_TYPE:
		psFunction->type = DROID_DESIGN_TYPE;
		break;
	case MAP_MARKER_TYPE:
		psFunction->type = MAP_MARKER_TYPE;
		break;
	case SKY_DOME_MAP_TYPE:
		psFunction->type = SKY_DOME_MAP_TYPE;
		break;
	default:
		DBERROR(("Unknown Function Type"));
		return FALSE;
	}

	//read the data in
	sscanf(pData, "%[^',']", &functionName);

	//allocate storage for the name
	storeName(psFunction, functionName);

	return TRUE;
}*/

BOOL loadProduction(char *pData)
{
	PRODUCTION_FUNCTION*	psFunction;
	//UBYTE					propType;
	STRING					functionName[MAX_NAME_SIZE], bodySize[MAX_NAME_SIZE];
	UDWORD					productionOutput;
	//STRING					propulsionType[MAX_NAME_SIZE];
	//PROPULSION_TYPES*		pPropulsionType;
/*#ifdef HASH_NAMES
	UDWORD	HashedName;
#endif*/
	//allocate storage
	psFunction = (PRODUCTION_FUNCTION *)MALLOC(sizeof(PRODUCTION_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Production Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(PRODUCTION_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION*)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = PRODUCTION_TYPE;

	//read the data in
	functionName[0] = '\0';
	//propulsionType[0] = '\0';
	bodySize[0] = '\0';
	sscanf(pData, "%[^','],%[^','],%d", functionName, bodySize,
		&productionOutput);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//get the propulsion stats pointer
/*	pPropulsionType = asPropulsionTypes;
	psFunction->propulsionType = 0;
#ifdef HASH_NAMES
	HashedName=HashString(propulsionType);
#endif
	for (i=0; i < numPropulsionTypes; i++)
	{
		//compare the names
#ifdef HASH_NAMES
		if (HashedName== pPropulsionType->NameHash)
#else
		if (!strcmp(propulsionType, pPropulsionType->pName))
#endif
		{
			psFunction->propulsionType = pPropulsionType;
			break;
		}
		pPropulsionType++;
	}
	//if haven't found the propulsion type, then problem
	if (!psFunction->propulsionType)
	{
		DBERROR(("Unknown Propulsion Type"));
		return FALSE;
	}
*/
	/*propType = getPropulsionType(propulsionType);
	if (propType == INVALID_PROP_TYPE)
	{
		DBERROR(("Unknown Propulsion Type - %s", propulsionType));
		return FALSE;
	}
	psFunction->propulsionType = propType;*/

	if (!getBodySize(bodySize, (UBYTE*)&psFunction->capacity))
	{

		ASSERT( FALSE, "loadProduction: unknown body size for %s",psFunction->pName );

		return FALSE;
	}

	//check prod output < UWORD_MAX
	if (productionOutput < UWORD_MAX)
	{
		psFunction->productionOutput = (UWORD)productionOutput;
	}
	else
	{

		ASSERT( FALSE, "loadProduction: production Output too big for %s",psFunction->pName );

		psFunction->productionOutput = 0;
	}

	return TRUE;
}

BOOL loadProductionUpgradeFunction(char *pData)
{
	PRODUCTION_UPGRADE_FUNCTION*	psFunction;
	STRING							functionName[MAX_NAME_SIZE];
	UDWORD							factory, cyborg, vtol;
	UDWORD outputModifier;

	//allocate storage
	psFunction = (PRODUCTION_UPGRADE_FUNCTION *)MALLOC(sizeof
		(PRODUCTION_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Production Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(PRODUCTION_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = PRODUCTION_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d,%d", functionName, &factory,
		&cyborg, &vtol,&outputModifier);


	psFunction->outputModifier=(UBYTE)outputModifier;
	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//set the factory flags
	if (factory)
	{
		psFunction->factory = TRUE;
	}
	else
	{
		psFunction->factory = FALSE;
	}
	if (cyborg)
	{
		psFunction->cyborgFactory = TRUE;
	}
	else
	{
		psFunction->cyborgFactory = FALSE;
	}
	if (vtol)
	{
		psFunction->vtolFactory = TRUE;
	}
	else
	{
		psFunction->vtolFactory = FALSE;
	}

	//increment the number of upgrades
	//numProductionUpgrades++;
	return TRUE;
}

BOOL loadResearchFunction(char *pData)
{
	RESEARCH_FUNCTION*			psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (RESEARCH_FUNCTION *)MALLOC(sizeof(RESEARCH_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Research Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(RESEARCH_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = RESEARCH_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", functionName, &psFunction->researchPoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}

BOOL loadReArmFunction(char *pData)
{
	REARM_FUNCTION*				psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (REARM_FUNCTION *)MALLOC(sizeof(REARM_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "ReArm Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(REARM_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = REARM_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", functionName, &psFunction->reArmPoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}


BOOL loadResearchUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, RESEARCH_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadPowerUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, POWER_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadRepairUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, REPAIR_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadDroidRepairUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, DROIDREPAIR_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadDroidECMUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, DROIDECM_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadDroidConstUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, DROIDCONST_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL loadReArmUpgradeFunction(char *pData)
{
	if (!loadUpgradeFunction(pData, REARM_UPGRADE_TYPE))
	{
		return FALSE;
	}

	return TRUE;
}

//generic load function for upgrade type
BOOL loadUpgradeFunction(char *pData, UBYTE type)
{
	STRING						functionName[MAX_NAME_SIZE];
	UDWORD						modifier;
	UPGRADE_FUNCTION			*psFunction;

	//allocate storage
	psFunction = (UPGRADE_FUNCTION *)MALLOC(sizeof(UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = type;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", functionName, &modifier);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	if (modifier > UWORD_MAX)
	{
		ASSERT( FALSE, "loadUpgradeFunction: modifier too great for %s", functionName );
		return FALSE;
	}

	//store the % upgrade
	psFunction->upgradePoints = (UWORD)modifier;

	return TRUE;
}

BOOL loadDroidBodyUpgradeFunction(char *pData)
{
	DROIDBODY_UPGRADE_FUNCTION		*psFunction;
	STRING							functionName[MAX_NAME_SIZE];
	UDWORD							modifier, armourKinetic, armourHeat,
									body, droid, cyborg;

	//allocate storage
	psFunction = (DROIDBODY_UPGRADE_FUNCTION *)MALLOC(
		sizeof(DROIDBODY_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "UnitBody Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(DROIDBODY_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = DROIDBODY_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d,%d,%d,%d", functionName, &modifier,
		&body, &armourKinetic,	&armourHeat, &droid, &cyborg);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	if (modifier > UWORD_MAX OR armourKinetic > UWORD_MAX OR
		armourHeat > UWORD_MAX OR body > UWORD_MAX)
	{
		ASSERT( FALSE,
			"loadUnitBodyUpgradeFunction: one or more modifiers too great" );
		return FALSE;
	}

	//store the % upgrades
	psFunction->upgradePoints = (UWORD)modifier;
	psFunction->body = (UWORD)body;
	psFunction->armourValue[WC_KINETIC] = (UWORD)armourKinetic;
	psFunction->armourValue[WC_HEAT] = (UWORD)armourHeat;
	if (droid)
	{
		psFunction->droid = TRUE;
	}
	else
	{
		psFunction->droid = FALSE;
	}
	if (cyborg)
	{
		psFunction->cyborg = TRUE;
	}
	else
	{
		psFunction->cyborg = FALSE;
	}

	return TRUE;
}

BOOL loadDroidSensorUpgradeFunction(char *pData)
{
	DROIDSENSOR_UPGRADE_FUNCTION	*psFunction;
	STRING							functionName[MAX_NAME_SIZE];
	UDWORD							modifier, range;

	//allocate storage
	psFunction = (DROIDSENSOR_UPGRADE_FUNCTION *)MALLOC(
		sizeof(DROIDSENSOR_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "UnitSensor Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(DROIDSENSOR_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = DROIDSENSOR_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d", functionName, &modifier, &range);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	if (modifier > UWORD_MAX OR range > UWORD_MAX)
	{
		ASSERT( FALSE,
			"loadUnitSensorUpgradeFunction: one or more modifiers too great" );
		return FALSE;
	}

	//store the % upgrades
	psFunction->upgradePoints = (UWORD)modifier;
	psFunction->range = (UWORD)range;

    return TRUE;
}

BOOL loadWeaponUpgradeFunction(char *pData)
{
	WEAPON_UPGRADE_FUNCTION*	psFunction;
	STRING						functionName[MAX_NAME_SIZE],
								weaponSubClass[MAX_NAME_SIZE];
	UDWORD						firePause, shortHit, longHit, damage,
								radiusDamage, incenDamage, radiusHit;

	//allocate storage
	psFunction = (WEAPON_UPGRADE_FUNCTION *)MALLOC(sizeof
		(WEAPON_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Weapon Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(WEAPON_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = WEAPON_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	weaponSubClass[0] = '\0';
	sscanf(pData, "%[^','],%[^','],%d,%d,%d,%d,%d,%d,%d", functionName,
		weaponSubClass, &firePause, &shortHit, &longHit, &damage, &radiusDamage,
		&incenDamage, &radiusHit);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	psFunction->subClass = getWeaponSubClass(weaponSubClass);
	if (psFunction->subClass == INVALID_SUBCLASS)
	{
		return FALSE;
	}

	//check none of the %increases are over UBYTE max
	if (firePause > UBYTE_MAX OR
		shortHit > UWORD_MAX OR
		longHit > UWORD_MAX OR
		damage > UWORD_MAX OR
		radiusDamage > UWORD_MAX OR
		incenDamage > UWORD_MAX OR
		radiusHit > UWORD_MAX)
	{
		debug( LOG_ERROR, "A percentage increase for Weapon Upgrade function is too large" );
		abort();
		return FALSE;
	}

	//copy the data across
	psFunction->firePause = (UBYTE)firePause;
	psFunction->shortHit = (UWORD)shortHit;
	psFunction->longHit = (UWORD)longHit;
	psFunction->damage = (UWORD)damage;
	psFunction->radiusDamage = (UWORD)radiusDamage;
	psFunction->incenDamage = (UWORD)incenDamage;
	psFunction->radiusHit = (UWORD)radiusHit;

	//increment the number of upgrades
	//numWeaponUpgrades++;

    return TRUE;
}

BOOL loadStructureUpgradeFunction(char *pData)
{
	STRUCTURE_UPGRADE_FUNCTION  *psFunction;
	STRING						functionName[MAX_NAME_SIZE];
	UDWORD						armour, body, resistance;

	//allocate storage
	psFunction = (STRUCTURE_UPGRADE_FUNCTION *)MALLOC(sizeof
		(STRUCTURE_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Structure Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(STRUCTURE_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = STRUCTURE_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d", functionName, &armour, &body, &resistance);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//check none of the %increases are over UWORD max
	if (armour > UWORD_MAX OR
		body > UWORD_MAX OR
		resistance > UWORD_MAX)
	{
		debug( LOG_ERROR, "A percentage increase for Structure Upgrade function is too large" );
		abort();
		return FALSE;
	}

	//copy the data across
	psFunction->armour = (UWORD)armour;
	psFunction->body = (UWORD)body;
	psFunction->resistance = (UWORD)resistance;

	return TRUE;
}

BOOL loadWallDefenceUpgradeFunction(char *pData)
{
	WALLDEFENCE_UPGRADE_FUNCTION  *psFunction;
	STRING						functionName[MAX_NAME_SIZE];
	UDWORD						armour, body;

	//allocate storage
	psFunction = (WALLDEFENCE_UPGRADE_FUNCTION *)MALLOC(sizeof
		(WALLDEFENCE_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "WallDefence Upgrade Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(WALLDEFENCE_UPGRADE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = WALLDEFENCE_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d", functionName, &armour, &body);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//check none of the %increases are over UWORD max
	if (armour > UWORD_MAX OR
		body > UWORD_MAX)
	{
		debug( LOG_ERROR, "A percentage increase for WallDefence Upgrade function is too large" );
		abort();
		return FALSE;
	}

	//copy the data across
	psFunction->armour = (UWORD)armour;
	psFunction->body = (UWORD)body;

	return TRUE;
}

/*BOOL loadBodyUpgradeFunction(char *pData)
{
	BODY_UPGRADE_FUNCTION*		psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (BODY_UPGRADE_FUNCTION *)MALLOC(sizeof
		(BODY_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Body Upgrade Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = BODY_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", &functionName, &psFunction->bodyPoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//increment the number of upgrades
	numBodyUpgrades++;

	return TRUE;
}*/

/*BOOL loadRadarMapFunction(char *pData)
{
	RADAR_MAP_FUNCTION*			psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (RADAR_MAP_FUNCTION *)MALLOC(sizeof
		(RADAR_MAP_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Radar Map Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = RADAR_MAP_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d", &functionName,
		&psFunction->radarDecayRate, &psFunction->radarRadius);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}*/

BOOL loadPowerGenFunction(char *pData)
{
	POWER_GEN_FUNCTION*			psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (POWER_GEN_FUNCTION *)MALLOC(sizeof
		(POWER_GEN_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Power Gen Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(POWER_GEN_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = POWER_GEN_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d,%d,%d,%d", functionName,
		&psFunction->powerOutput, &psFunction->powerMultiplier,
		&psFunction->criticalMassChance, &psFunction->criticalMassRadius,
		&psFunction->criticalMassDamage, &psFunction->radiationDecayTime);


	if(bMultiPlayer)
	{
		modifyResources(psFunction);
	}


	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}

BOOL loadResourceFunction(char *pData)
{
	RESOURCE_FUNCTION			*psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (RESOURCE_FUNCTION *)MALLOC(sizeof
		(RESOURCE_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Resource Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(RESOURCE_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
 	psFunction->type = RESOURCE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", functionName, &psFunction->maxPower);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}

/*BOOL loadPowerRegFunction(char *pData)
{
	POWER_REG_FUNCTION*			psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (POWER_REG_FUNCTION *)MALLOC(sizeof
		(POWER_REG_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Power Reg Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
 	psFunction->type = POWER_REG_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", &functionName, &psFunction->maxPower);


	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}*/

/*BOOL loadPowerRelayFunction(char *pData)
{
	POWER_RELAY_FUNCTION*			psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (POWER_RELAY_FUNCTION *)MALLOC(sizeof
		(POWER_RELAY_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Power Relay Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = POWER_RELAY_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d", &functionName,
		&psFunction->powerRelayType, &psFunction->powerRelayRange);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}*/

BOOL loadRepairDroidFunction(char *pData)
{
	REPAIR_DROID_FUNCTION*		psFunction;
	STRING						functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (REPAIR_DROID_FUNCTION *)MALLOC(sizeof
		(REPAIR_DROID_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Repair Droid Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(REPAIR_DROID_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = REPAIR_DROID_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", functionName,
		&psFunction->repairPoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}

/*BOOL loadDefensiveStructFunction(char *pData)
{
	//pData;
	//DBERROR(("Defensive Structure Function is not longer used - \
	//	do not allocate it to a Structure!"));
	//return FALSE;
	DEFENSIVE_STRUCTURE_FUNCTION*	psFunction;
	UDWORD							i;
	STRING							functionName[MAX_NAME_SIZE];
	STRING							sensorType[MAX_NAME_SIZE];
	STRING							ecmType[MAX_NAME_SIZE];
	SENSOR_STATS*					pSensorType;
	ECM_STATS*						pECMType;

	//allocate storage
	psFunction = (DEFENSIVE_STRUCTURE_FUNCTION *)MALLOC(
		sizeof(DEFENSIVE_STRUCTURE_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Defensive Structure Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = DEFENSIVE_STRUCTURE_TYPE;

	//read the data in
	sscanf(pData, "%[^','],%[^','],%[^','],%d", &functionName, &ecmType,
		&sensorType, &psFunction->weaponCapacity);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//get the sensor stats pointer
	if (!strcmp(sensorType,"0"))
	{
		psFunction->pSensor = NULL;
	}
	else
	{
		pSensorType = asSensorStats;
		for (i=0; i < numSensorStats; i++)
		{
			//compare the names
			if (!strcmp(sensorType, pSensorType->pName))
			{
				psFunction->pSensor = pSensorType;
				break;
			}
			pSensorType++;
		}
	}
	//get the ecm stats pointer
	if (!strcmp(ecmType,"0"))
	{
		psFunction->pECM = NULL;
	}
	else
	{
		pECMType = asECMStats;
		for (i=0; i < numECMStats; i++)
		{
			//compare the names
			if (!strcmp(ecmType, pECMType->pName))
			{
				psFunction->pECM = pECMType;
				break;
			}
			pECMType++;
		}
	}
	return TRUE;
}*/

/*BOOL loadHQFunction(SBYTE *pData)
{
	HQ_FUNCTION*		psFunction;
	STRING				functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (HQ_FUNCTION *)MALLOC(sizeof(HQ_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("HQ Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = HQ_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d", &functionName,
		&psFunction->power);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	return TRUE;
}*/

/*BOOL loadArmourUpgradeFunction(SBYTE *pData)
{
	ARMOUR_UPGRADE_FUNCTION*	psFunction;
//	UDWORD						i;
	STRING						functionName[MAX_NAME_SIZE];
	//STRING						armourType[50];
//	ARMOUR_STATS*				pArmourType;

	//allocate storage
	psFunction = (ARMOUR_UPGRADE_FUNCTION *)MALLOC(sizeof(ARMOUR_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Armour Upgrade Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = ARMOUR_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d", &functionName,
		&psFunction->buildPoints, &psFunction->powerRequired, &psFunction->armourPoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//get the armour stats pointer
	//pArmourType = asArmourStats;
	//psFunction->pArmour = NULL;
	//for (i=0; i < numArmourStats; i++)
	//{
		//compare the names
	//	if (!strcmp(armourType, pArmourType->pName))
	//	{
	//		psFunction->pArmour = pArmourType;
	//		break;
	//	}
	//	pArmourType++;
	//}
	//if not found the armour stat then problem
	//if (!psFunction->pArmour)
	//{
	//	DBERROR(("Armour Type invalid"));
	//	return FALSE;
	//}

	//increment the number of upgrades
	numArmourUpgrades++;

	return TRUE;
}*/

/*BOOL loadRepairUpgradeFunction(SBYTE *pData)
{
	REPAIR_UPGRADE_FUNCTION*	psFunction;
	UDWORD						i;
	STRING						functionName[MAX_NAME_SIZE];
	STRING						repairType[MAX_NAME_SIZE];
	REPAIR_STATS*				pRepairType;

#ifdef HASH_NAMES
	UDWORD	HashedName;
#endif
	//allocate storage
	psFunction = (REPAIR_UPGRADE_FUNCTION *)MALLOC(sizeof(REPAIR_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Repair Upgrade Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = REPAIR_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	repairType[0] = '\0';
	sscanf(pData, "%[^','],%[^','],%d,%d,%d", &functionName,
		&repairType, &psFunction->repairPoints, &psFunction->buildPoints,
		&psFunction->powerRequired);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	if (!getResourceName(repairType))
	{
		return FALSE;
	}


	//get the repair stats pointer
	pRepairType = asRepairStats;
	psFunction->pRepair = NULL;
#ifdef HASH_NAMES
	HashedName=HashString(repairType);
#endif


	for (i=0; i < numRepairStats; i++)
	{
		//compare the names
#ifdef HASH_NAMES
		if (HashedName== pRepairType->NameHash)
#else
		if (!strcmp(repairType, pRepairType->pName))
#endif
		{
			psFunction->pRepair = pRepairType;
			break;
		}
		pRepairType++;
	}
	//if not found the repair stats then problem
	if (!psFunction->pRepair)
	{
		DBERROR(("Repair Stats Invalid for function - %s", functionName));
		return FALSE;
	}
	//increment the number of upgrades
	numRepairUpgrades++;

	return TRUE;
}*/

/*BOOL loadResistanceUpgradeFunction(SBYTE *pData)
{
	RESISTANCE_UPGRADE_FUNCTION*		psFunction;
	STRING								functionName[MAX_NAME_SIZE];

	//allocate storage
	psFunction = (RESISTANCE_UPGRADE_FUNCTION *)MALLOC(sizeof
		(RESISTANCE_UPGRADE_FUNCTION));
	if (psFunction == NULL)
	{
		DBERROR(("Resistance Upgrade Function - Out of memory"));
		return FALSE;
	}

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION *)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = RESISTANCE_UPGRADE_TYPE;

	//read the data in
	functionName[0] = '\0';
	sscanf(pData, "%[^','],%d,%d,%d,%d", &functionName,
		&psFunction->resistanceUpgrade, &psFunction->buildPoints,
		&psFunction->powerRequired, &psFunction->resistancePoints);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//increment the number of upgrades
	numResistanceUpgrades++;

	return TRUE;
}*/

/*loads the corner stat to use for a particular wall stat */
BOOL loadWallFunction(char *pData)
{
	WALL_FUNCTION			*psFunction;
//	UDWORD					i;
	STRING					functionName[MAX_NAME_SIZE];
	STRING					structureName[MAX_NAME_SIZE];
//	STRUCTURE_STATS			*pStructStat;

	//allocate storage
	psFunction = (WALL_FUNCTION *)MALLOC(sizeof(WALL_FUNCTION));
	if (psFunction == NULL)
	{
		debug( LOG_ERROR, "Wall Function - Out of memory" );
		abort();
		return FALSE;
	}
	memset(psFunction, 0, sizeof(WALL_FUNCTION));

	//store the pointer in the Function Array
	*asFunctions = (FUNCTION*)psFunction;
	psFunction->ref = REF_FUNCTION_START + numFunctions;
	numFunctions++;
	asFunctions++;

	//set the type of function
	psFunction->type = WALL_TYPE;

	//read the data in
	functionName[0] = '\0';
	structureName[0] = '\0';
	sscanf(pData, "%[^','],%[^','],%*d", functionName, structureName);

	//allocate storage for the name
	storeName((FUNCTION *)psFunction, functionName);

	//store the structure name - cannot set the stat pointer here because structures
	//haven't been loaded in yet!
	/*psFunction->pStructName = (STRING *)MALLOC(strlen(structureName)+1);
	if (psFunction->pStructName == NULL)
	{
		DBERROR(("Function Name - Out of memory"));
		return FALSE;
	}
	strcpy(psFunction->pStructName,structureName);*/
#ifdef HASH_NAMES
	psFunction->StructNameHash=HashString(structureName);
#else
	if (!allocateName(&psFunction->pStructName, structureName))
	{
		debug( LOG_ERROR, "Structure Stats Invalid for function - %s", functionName );
		abort();
		return FALSE;
	}
#endif
	psFunction->pCornerStat = NULL;

	return TRUE;
}

void productionUpgrade(FUNCTION *pFunction, UBYTE player)
{
	PRODUCTION_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (PRODUCTION_UPGRADE_FUNCTION	*)pFunction;

	//check upgrades increase all values
	if (pUpgrade->factory)
	{
		if (asProductionUpgrade[player][FACTORY_FLAG].modifier <
			pUpgrade->outputModifier)
		{
			asProductionUpgrade[player][FACTORY_FLAG].modifier =
				pUpgrade->outputModifier;
		}
	}
	if (pUpgrade->cyborgFactory)
	{
		if (asProductionUpgrade[player][CYBORG_FLAG].modifier <
			pUpgrade->outputModifier)
		{
			asProductionUpgrade[player][CYBORG_FLAG].modifier =
				pUpgrade->outputModifier;
		}
	}
	if (pUpgrade->vtolFactory)
	{
		if (asProductionUpgrade[player][VTOL_FLAG].modifier <
			pUpgrade->outputModifier)
		{
			asProductionUpgrade[player][VTOL_FLAG].modifier =
				pUpgrade->outputModifier;
		}
	}
}

void researchUpgrade(FUNCTION *pFunction, UBYTE player)
{
	RESEARCH_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (RESEARCH_UPGRADE_FUNCTION	*)pFunction;

	//check upgrades increase all values
	if (asResearchUpgrade[player].modifier < pUpgrade->upgradePoints)
	{
		asResearchUpgrade[player].modifier = pUpgrade->upgradePoints;
	}
}

void repairFacUpgrade(FUNCTION *pFunction, UBYTE player)
{
	REPAIR_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (REPAIR_UPGRADE_FUNCTION	*)pFunction;

	//check upgrades increase all values
	if (asRepairFacUpgrade[player].modifier < pUpgrade->upgradePoints)
	{
		asRepairFacUpgrade[player].modifier = pUpgrade->upgradePoints;
	}
}

void powerUpgrade(FUNCTION *pFunction, UBYTE player)
{
	POWER_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (POWER_UPGRADE_FUNCTION	*)pFunction;

	//check upgrades increase all values
	if (asPowerUpgrade[player].modifier < pUpgrade->upgradePoints)
	{
		asPowerUpgrade[player].modifier = pUpgrade->upgradePoints;
	}
}

void reArmUpgrade(FUNCTION *pFunction, UBYTE player)
{
	REARM_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (REARM_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values
	if (asReArmUpgrade[player].modifier < pUpgrade->upgradePoints)
	{
		asReArmUpgrade[player].modifier = pUpgrade->upgradePoints;
	}
}

void structureBodyUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	UWORD	increase, prevBaseBody, newBaseBody;

	switch(psBuilding->pStructureType->type)
	{
	case REF_WALL:
	case REF_WALLCORNER:
	case REF_DEFENSE:
	case REF_BLASTDOOR:
		increase = ((WALLDEFENCE_UPGRADE_FUNCTION *)pFunction)->body;
		break;
	default:
		increase = ((STRUCTURE_UPGRADE_FUNCTION *)pFunction)->body;
		break;
	}

	prevBaseBody = (UWORD)structureBody(psBuilding);
	//newBaseBody = (UWORD)(psBuilding->pStructureType->bodyPoints + (psBuilding->
	//	pStructureType->bodyPoints * increase) / 100);
	newBaseBody = (UWORD)(structureBaseBody(psBuilding) +
		(structureBaseBody(psBuilding) * increase) / 100);

	if (newBaseBody > prevBaseBody)
	{
		psBuilding->body = (UWORD)((psBuilding->body * newBaseBody) / prevBaseBody);
		//psBuilding->baseBodyPoints = newBaseBody;
	}
}

void structureArmourUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	UWORD	increase, prevBaseArmour, newBaseArmour;

	switch(psBuilding->pStructureType->type)
	{
	case REF_WALL:
	case REF_WALLCORNER:
	case REF_DEFENSE:
	case REF_BLASTDOOR:
		increase = ((WALLDEFENCE_UPGRADE_FUNCTION *)pFunction)->armour;
		break;
	default:
		increase = ((STRUCTURE_UPGRADE_FUNCTION *)pFunction)->armour;
		break;
	}

	prevBaseArmour = (UWORD)structureArmour(psBuilding->pStructureType, psBuilding->player);
	newBaseArmour = (UWORD)(psBuilding->pStructureType->armourValue + (psBuilding->
		pStructureType->armourValue * increase) / 100);

	if (newBaseArmour > prevBaseArmour)
	{
		psBuilding->armour = (UWORD)((psBuilding->armour * newBaseArmour) / prevBaseArmour);
	}
}

void structureResistanceUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	UWORD	increase, prevBaseResistance, newBaseResistance;

	increase = ((STRUCTURE_UPGRADE_FUNCTION *)pFunction)->resistance;

	prevBaseResistance = (UWORD)structureResistance(psBuilding->pStructureType,
		psBuilding->player);
	newBaseResistance = (UWORD)(psBuilding->pStructureType->resistance + (psBuilding
		->pStructureType->resistance * increase) / 100);

	if (newBaseResistance > prevBaseResistance)
	{
		psBuilding->resistance = (UWORD)((psBuilding->resistance * newBaseResistance) /
			prevBaseResistance);
	}
}

void structureProductionUpgrade(STRUCTURE *psBuilding)
{
	FACTORY						*pFact;
	PRODUCTION_FUNCTION			*pFactFunc;
	UDWORD						type, baseOutput, i;
    STRUCTURE_STATS             *psStat;

	switch(psBuilding->pStructureType->type)
	{
	case REF_FACTORY:
		type = FACTORY_FLAG;
		break;
	case REF_CYBORG_FACTORY:
		type = CYBORG_FLAG;
		break;
	case REF_VTOL_FACTORY:
		type = VTOL_FLAG;
		break;
	default:
		ASSERT( FALSE, "structureProductionUpgrade: Invalid factory type" );
		return;
	}

	//upgrade the Output
	pFact = (FACTORY*)psBuilding->pFunctionality;
	ASSERT( PTRVALID(pFact, sizeof(FACTORY)),
		"structureProductionUpgrade: invalid Factory pointer" );

	pFactFunc = (PRODUCTION_FUNCTION *)psBuilding->pStructureType->asFuncList[0];
	ASSERT( PTRVALID(pFactFunc, sizeof(PRODUCTION_FUNCTION)),
		"structureProductionUpgrade: invalid Function pointer" );

    //current base value depends on whether there are modules attached to the structure
    baseOutput = pFactFunc->productionOutput;
    psStat = getModuleStat(psBuilding);
    if (psStat)
    {
        for (i = 0; i < pFact->capacity; i++)
        {
            baseOutput += ((PRODUCTION_FUNCTION*)psStat->asFuncList[0])->productionOutput;
        }
    }

	pFact->productionOutput = (UBYTE)(baseOutput + (pFactFunc->productionOutput *
		asProductionUpgrade[psBuilding->player][type].modifier) / 100);
}

void structureResearchUpgrade(STRUCTURE *psBuilding)
{
	RESEARCH_FACILITY			*pRes;
	RESEARCH_FUNCTION			*pResFunc;
    UDWORD                       baseOutput;
    STRUCTURE_STATS             *psStat;

	//upgrade the research points
	pRes = (RESEARCH_FACILITY*)psBuilding->pFunctionality;
	ASSERT( PTRVALID(pRes, sizeof(RESEARCH_FACILITY)),
		"structureResearchUpgrade: invalid Research pointer" );

	pResFunc = (RESEARCH_FUNCTION *)psBuilding->pStructureType->asFuncList[0];
	ASSERT( PTRVALID(pResFunc, sizeof(RESEARCH_FUNCTION)),
		"structureResearchUpgrade: invalid Function pointer" );

    //current base value depends on whether there are modules attached to the structure
    baseOutput = pResFunc->researchPoints;
    psStat = getModuleStat(psBuilding);
    if (psStat)
    {
        if (pRes->capacity)
        {
            baseOutput += ((RESEARCH_FUNCTION*)psStat->asFuncList[0])->researchPoints;
        }
    }
	pRes->researchPoints = baseOutput + (pResFunc->researchPoints *
		asResearchUpgrade[psBuilding->player].modifier) / 100;
}

void structureReArmUpgrade(STRUCTURE *psBuilding)
{
	REARM_PAD					*pPad;
	REARM_FUNCTION				*pPadFunc;

	//upgrade the reArm points
	pPad = (REARM_PAD*)psBuilding->pFunctionality;
	ASSERT( PTRVALID(pPad, sizeof(REARM_PAD)),
		"structureReArmUpgrade: invalid ReArm pointer" );

	pPadFunc = (REARM_FUNCTION *)psBuilding->pStructureType->asFuncList[0];
	ASSERT( PTRVALID(pPadFunc, sizeof(REARM_FUNCTION)),
		"structureReArmUpgrade: invalid Function pointer" );

	pPad->reArmPoints = pPadFunc->reArmPoints + (pPadFunc->reArmPoints *
		asReArmUpgrade[psBuilding->player].modifier) / 100;
}

void structurePowerUpgrade(STRUCTURE *psBuilding)
{
	POWER_GEN					*pPowerGen;
	POWER_GEN_FUNCTION			*pPGFunc;
    UDWORD                       baseOutput;
    STRUCTURE_STATS             *psStat;

	//upgrade the research points
	pPowerGen = (POWER_GEN*)psBuilding->pFunctionality;
	ASSERT( PTRVALID(pPowerGen, sizeof(POWER_GEN)),
		"structurePowerUpgrade: invalid Power Gen pointer" );

	pPGFunc = (POWER_GEN_FUNCTION *)psBuilding->pStructureType->asFuncList[0];
	ASSERT( PTRVALID(pPGFunc, sizeof(POWER_GEN_FUNCTION)),
		"structurePowerUpgrade: invalid Function pointer" );

    //current base value depends on whether there are modules attached to the structure
    baseOutput = pPGFunc->powerMultiplier;
    psStat = getModuleStat(psBuilding);
    if (psStat)
    {
        if (pPowerGen->capacity)
        {
            baseOutput += ((POWER_GEN_FUNCTION*)psStat->asFuncList[0])->powerOutput;
        }
    }
	pPowerGen->multiplier = baseOutput + (pPGFunc->powerMultiplier *
		asPowerUpgrade[psBuilding->player].modifier) / 100;
}

void structureRepairUpgrade(STRUCTURE *psBuilding)
{
	REPAIR_FACILITY			*pRepair;
	REPAIR_DROID_FUNCTION	*pRepairFunc;

	//upgrade the research points
	pRepair = (REPAIR_FACILITY*)psBuilding->pFunctionality;
	ASSERT( PTRVALID(pRepair, sizeof(REPAIR_FACILITY)),
		"structureRepairUpgrade: invalid Repair pointer" );

	pRepairFunc = (REPAIR_DROID_FUNCTION *)psBuilding->pStructureType->asFuncList[0];
	ASSERT( PTRVALID(pRepairFunc, sizeof(REPAIR_DROID_FUNCTION)),
		"structureRepairUpgrade: invalid Function pointer" );

	pRepair->power = pRepairFunc->repairPoints + (pRepairFunc->repairPoints *
		asRepairFacUpgrade[psBuilding->player].modifier) / 100;
}

void structureSensorUpgrade(STRUCTURE *psBuilding)
{
	//reallocate the sensor range and power since the upgrade
	if (psBuilding->pStructureType->pSensor)
	{
		psBuilding->sensorRange = (UWORD)sensorRange(psBuilding->pStructureType->
			pSensor, psBuilding->player);
		psBuilding->sensorPower = (UWORD)sensorPower(psBuilding->pStructureType->
			pSensor, psBuilding->player);
	}
	else
	{
		//give them the default sensor for droids if not
		psBuilding->sensorRange = (UWORD)sensorRange(asSensorStats +
			aDefaultSensor[psBuilding->player], psBuilding->player);
		psBuilding->sensorPower = (UWORD)sensorPower(asSensorStats +
			aDefaultSensor[psBuilding->player], psBuilding->player);
	}
}

void structureECMUpgrade(STRUCTURE *psBuilding)
{
	//reallocate the sensor range and power since the upgrade
	if (psBuilding->pStructureType->pECM)
	{
		psBuilding->ecmPower = (UWORD)ecmPower(psBuilding->pStructureType->pECM,
			psBuilding->player);
	}
	else
	{
		psBuilding->ecmPower = 0;
	}
}

void droidSensorUpgrade(DROID *psDroid)
{
	//reallocate the sensor range and power since the upgrade
	psDroid->sensorRange = sensorRange((asSensorStats + psDroid->asBits
		[COMP_SENSOR].nStat), psDroid->player);
	psDroid->sensorPower = sensorPower((asSensorStats + psDroid->asBits
		[COMP_SENSOR].nStat), psDroid->player);
}

void droidECMUpgrade(DROID *psDroid)
{
	//reallocate the ecm power since the upgrade
	psDroid->ECMMod = ecmPower((asECMStats + psDroid->asBits[COMP_ECM].nStat),
		psDroid->player);
}

void droidBodyUpgrade(FUNCTION *pFunction, DROID *psDroid)
{
	UDWORD	increase, prevBaseBody, newBaseBody, base;
    DROID   *psCurr;

	increase = ((DROIDBODY_UPGRADE_FUNCTION*)pFunction)->body;

	prevBaseBody = psDroid->originalBody;
	base = calcDroidBaseBody(psDroid);
	newBaseBody =  base + (base * increase) / 100;

	if (newBaseBody > prevBaseBody)
	{
		psDroid->body = (psDroid->body * newBaseBody) / prevBaseBody;
		psDroid->originalBody = newBaseBody;
	}
    //if a transporter droid then need to upgrade the contents
    if (psDroid->droidType == DROID_TRANSPORTER)
    {
        for (psCurr = psDroid->psGroup->psList; psCurr != NULL; psCurr =
            psCurr->psGrpNext)
        {
            if (psCurr != psDroid)
            {
                droidBodyUpgrade(pFunction, psCurr);
            }
        }
    }
}

/*void armourUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	psBuilding->armour = psBuilding->pStructureType->armourValue + (psBuilding->
		pStructureType->armourValue *((	ARMOUR_UPGRADE_FUNCTION *)pFunction)->
		armourPoints) / 100;
}*/

/*void repairUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	psBuilding->repair = psBuilding->pStructureType->repairSystem + (psBuilding->
		pStructureType->repairSystem *((REPAIR_UPGRADE_FUNCTION *)pFunction)->
		repairPoints) / 100;
}*/

/*void bodyUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	UDWORD	increment;

	increment = (psBuilding->pStructureType->bodyPoints *((
		BODY_UPGRADE_FUNCTION *)pFunction)->bodyPoints) / 100;

	psBuilding->body += increment;
	//upgrade the base body points
	psBuilding->baseBodyPoints += increment;
}*/

/*void resistanceUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding)
{
	psBuilding->resistance = psBuilding->pStructureType->resistance + (psBuilding->
		pStructureType->resistance *((RESISTANCE_UPGRADE_FUNCTION *)pFunction)->
		resistancePoints) / 100;

	//I'm not convinced this function is ever going to get used but if it does then
	we will have to keep a copy of the baseResistancePoints per Structure like we do
	with the body points, but I don't want to increase the size of STRUCTURE if we
	don't need to! AB 01/07/98
	ASSERT( TRUE,
		"resistanceUpgrade - for this function to work, there has to be a code change" );
}*/

//upgrade the weapon stats for the correct subclass
void weaponUpgrade(FUNCTION *pFunction, UBYTE player)
{
	WEAPON_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (WEAPON_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asWeaponUpgrade[player][pUpgrade->subClass].firePause < pUpgrade->firePause)
	{
        //make sure don't go less than 100%
        if (pUpgrade->firePause > 100)
        {
            pUpgrade->firePause = 100;
        }
		asWeaponUpgrade[player][pUpgrade->subClass].firePause = pUpgrade->firePause;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].shortHit < pUpgrade->shortHit)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].shortHit = pUpgrade->shortHit;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].longHit < pUpgrade->longHit)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].longHit = pUpgrade->longHit;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].damage < pUpgrade->damage)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].damage = pUpgrade->damage;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].radiusDamage < pUpgrade->radiusDamage)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].radiusDamage = pUpgrade->radiusDamage;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].incenDamage < pUpgrade->incenDamage)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].incenDamage = pUpgrade->incenDamage;
	}
	if (asWeaponUpgrade[player][pUpgrade->subClass].radiusHit < pUpgrade->radiusHit)
	{
		asWeaponUpgrade[player][pUpgrade->subClass].radiusHit = pUpgrade->radiusHit;
	}
}

//upgrade the sensor stats
void sensorUpgrade(FUNCTION *pFunction, UBYTE player)
{
	DROIDSENSOR_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (DROIDSENSOR_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asSensorUpgrade[player].range < pUpgrade->range)
	{
		asSensorUpgrade[player].range = pUpgrade->range;
	}
	if (asSensorUpgrade[player].power < pUpgrade->upgradePoints)
	{
		asSensorUpgrade[player].power = pUpgrade->upgradePoints;
	}
}

//upgrade the repair stats
void repairUpgrade(FUNCTION *pFunction, UBYTE player)
{
	DROIDREPAIR_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (DROIDREPAIR_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asRepairUpgrade[player].repairPoints < pUpgrade->upgradePoints)
	{
		asRepairUpgrade[player].repairPoints = pUpgrade->upgradePoints;
	}
}

//upgrade the repair stats
void ecmUpgrade(FUNCTION *pFunction, UBYTE player)
{
	DROIDECM_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (DROIDECM_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asECMUpgrade[player].power < pUpgrade->upgradePoints)
	{
		asECMUpgrade[player].power = pUpgrade->upgradePoints;
	}
}

//upgrade the repair stats
void constructorUpgrade(FUNCTION *pFunction, UBYTE player)
{
	DROIDCONSTR_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (DROIDCONSTR_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asConstUpgrade[player].constructPoints < pUpgrade->upgradePoints)
	{
		asConstUpgrade[player].constructPoints = pUpgrade->upgradePoints;
	}
}

//upgrade the body stats
void bodyUpgrade(FUNCTION *pFunction, UBYTE player)
{
	DROIDBODY_UPGRADE_FUNCTION		*pUpgrade;
	UBYTE							inc;

	pUpgrade = (DROIDBODY_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (pUpgrade->droid)
	{
		if (asBodyUpgrade[player][DROID_BODY_UPGRADE].powerOutput <
			pUpgrade->upgradePoints)
		{
			asBodyUpgrade[player][DROID_BODY_UPGRADE].powerOutput =
				pUpgrade->upgradePoints;
		}
		if (asBodyUpgrade[player][DROID_BODY_UPGRADE].body <
			pUpgrade->body)
		{
			asBodyUpgrade[player][DROID_BODY_UPGRADE].body =
				pUpgrade->body;
		}
		for (inc=0; inc < NUM_WEAPON_CLASS; inc++)
		{
			if (asBodyUpgrade[player][DROID_BODY_UPGRADE].armourValue[inc] <
				pUpgrade->armourValue[inc])
			{
				asBodyUpgrade[player][DROID_BODY_UPGRADE].armourValue[inc] =
					pUpgrade->armourValue[inc];
			}
		}
	}
	if (pUpgrade->cyborg)
	{
		if (asBodyUpgrade[player][CYBORG_BODY_UPGRADE].powerOutput <
			pUpgrade->upgradePoints)
		{
			asBodyUpgrade[player][CYBORG_BODY_UPGRADE].powerOutput =
				pUpgrade->upgradePoints;
		}
		if (asBodyUpgrade[player][CYBORG_BODY_UPGRADE].body <
			pUpgrade->body)
		{
			asBodyUpgrade[player][CYBORG_BODY_UPGRADE].body =
				pUpgrade->body;
		}
		for (inc=0; inc < NUM_WEAPON_CLASS; inc++)
		{
			if (asBodyUpgrade[player][CYBORG_BODY_UPGRADE].armourValue[inc] <
				pUpgrade->armourValue[inc])
			{
				asBodyUpgrade[player][CYBORG_BODY_UPGRADE].armourValue[inc] =
					pUpgrade->armourValue[inc];
			}
		}
	}
}

//upgrade the structure stats for the correct player
void structureUpgrade(FUNCTION *pFunction, UBYTE player)
{
	STRUCTURE_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (STRUCTURE_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asStructureUpgrade[player].armour < pUpgrade->armour)
	{
		asStructureUpgrade[player].armour = pUpgrade->armour;
	}
	if (asStructureUpgrade[player].body < pUpgrade->body)
	{
		asStructureUpgrade[player].body = pUpgrade->body;
	}
	if (asStructureUpgrade[player].resistance < pUpgrade->resistance)
	{
		asStructureUpgrade[player].resistance = pUpgrade->resistance;
	}
}

//upgrade the wall/Defence structure stats for the correct player
void wallDefenceUpgrade(FUNCTION *pFunction, UBYTE player)
{
	WALLDEFENCE_UPGRADE_FUNCTION		*pUpgrade;

	pUpgrade = (WALLDEFENCE_UPGRADE_FUNCTION *)pFunction;

	//check upgrades increase all values!
	if (asWallDefenceUpgrade[player].armour < pUpgrade->armour)
	{
		asWallDefenceUpgrade[player].armour = pUpgrade->armour;
	}
	if (asWallDefenceUpgrade[player].body < pUpgrade->body)
	{
		asWallDefenceUpgrade[player].body = pUpgrade->body;
	}
}

/*upgrades the droids inside a Transporter uwith the appropriate upgrade function*/
void upgradeTransporterDroids(DROID *psTransporter,
                              void(*pUpgradeFunction)(DROID *psDroid))
{
    DROID   *psCurr;

    ASSERT( psTransporter->droidType == DROID_TRANSPORTER,
        "upgradeTransporterUnits: invalid unit type" );

    //loop thru' each unit in the Transporter
    for (psCurr = psTransporter->psGroup->psList; psCurr != NULL; psCurr =
        psCurr->psGrpNext)
    {
        if (psCurr != psTransporter)
        {
            //apply upgrade if not the transporter itself
            pUpgradeFunction(psCurr);
        }
    }
}

BOOL FunctionShutDown()
{
	UDWORD		inc;//, player;
	FUNCTION	*pFunction, **pStartList = asFunctions;

	for (inc=0; inc < numFunctions; inc++)
	{
		pFunction = *asFunctions;
#ifndef HASH_NAMES
		FREE(pFunction->pName);
#endif

//#ifndef RESOURCE_NAMES
#if !defined (RESOURCE_NAMES) && !defined(STORE_RESOURCE_ID)
		if (pFunction->type == WALL_TYPE)
		{
			FREE(((WALL_FUNCTION *)pFunction)->pStructName);
		}
#endif
		FREE (pFunction);
		asFunctions++;
	}
	FREE (pStartList);

	//free the Upgrade lists
	/*for (player=0; player < MAX_PLAYERS; player++)
	{
		FREE(apProductionUpgrades[player]);
		//FREE(apBodyUpgrades[player]);
		//FREE(apRepairUpgrades[player]);
		//FREE(apResistanceUpgrades[player]);
		FREE(apResearchUpgrades[player]);
		//FREE(apArmourUpgrades[player]);
		//FREE(apWeaponUpgrades[player]);
	}*/
	return TRUE;
}

/*Returns the Function type based on the string - used for reading in data */
UDWORD functionType(char* pType)
{
	if (!strcmp(pType,"Production"))
	{
		return PRODUCTION_TYPE;
	}
	if (!strcmp(pType,"Production Upgrade"))
	{
		return PRODUCTION_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"Research"))
	{
		return RESEARCH_TYPE;
	}
	if (!strcmp(pType,"Research Upgrade"))
	{
		return RESEARCH_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"Power Generator"))
	{
		return POWER_GEN_TYPE;
	}
	if (!strcmp(pType,"Resource"))
	{
		return RESOURCE_TYPE;
	}
	if (!strcmp(pType,"Repair Droid"))
	{
		return REPAIR_DROID_TYPE;
	}
	if (!strcmp(pType,"Weapon Upgrade"))
	{
		return WEAPON_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"Wall Function"))
	{
		return WALL_TYPE;
	}
	if (!strcmp(pType,"Structure Upgrade"))
	{
		return STRUCTURE_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"WallDefence Upgrade"))
	{
		return WALLDEFENCE_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"Power Upgrade"))
	{
		return POWER_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"Repair Upgrade"))
	{
		return REPAIR_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"VehicleRepair Upgrade"))
	{
		return DROIDREPAIR_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"VehicleECM Upgrade"))
	{
		return DROIDECM_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"VehicleConst Upgrade"))
	{
		return DROIDCONST_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"VehicleBody Upgrade"))
	{
		return DROIDBODY_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"VehicleSensor Upgrade"))
	{
		return DROIDSENSOR_UPGRADE_TYPE;
	}
	if (!strcmp(pType,"ReArm"))
	{
		return REARM_TYPE;
	}
	if (!strcmp(pType,"ReArm Upgrade"))
	{
		return REARM_UPGRADE_TYPE;
	}

	/*if (!strcmp(pType,"Radar Map"))
	{
		return RADAR_MAP_TYPE;
	}*/
	/*if (!strcmp(pType,"Power Regulator"))
	{
		return POWER_REG_TYPE;
	}*/
	/*if (!strcmp(pType,"Power Relay"))
	{
		return POWER_RELAY_TYPE;
	}*/
	/*if (!strcmp(pType,"Defensive Structure"))
	{
		return DEFENSIVE_STRUCTURE_TYPE;
	}*/
	/*if (!strcmp(pType,"Armour Upgrade"))
	{
		return ARMOUR_UPGRADE_TYPE;
	}*/
	/*if (!strcmp(pType,"Repair Upgrade"))
	{
		return REPAIR_UPGRADE_TYPE;
	}*/
	/*if (!strcmp(pType,"Resistance Upgrade"))
	{
		return RESISTANCE_UPGRADE_TYPE;
	}*/
/*	if (!strcmp(pType,"Droid Design"))
	{
		return DROID_DESIGN_TYPE;
	}
	if (!strcmp(pType,"Map Marker"))
	{
		return MAP_MARKER_TYPE;
	}
	if (!strcmp(pType,"Sky Dome Map"))
	{
		return SKY_DOME_MAP_TYPE;
	}*/
	/*if (!strcmp(pType,"Body Upgrade"))
	{
		return BODY_UPGRADE_TYPE;
	}*/
	/*if (!strcmp(pType,"HQ"))
	{
		return HQ_TYPE;
	}*/

	ASSERT( FALSE, "Unknown Function Type" );
	return 0;
}
