Exemplo n.º 1
0
bool CAeonEngine::OpenTableDefinitions (void)

//	OpenTableDefinitions
//
//	Opens and reads all tables in all volumes. Note that we have no idea what
//	could have happened since our last boot--someone could have copied files
//	all over the place. We make almost no assumptions.

	{
	CSmartLock Lock(m_cs);

	int i, j;
	CString sError;

	//	Loop over all volumes and end up with a list of tables and volumes

	TSortMap<CString, TArray<CString>> Tables;
	for (i = 0; i < m_LocalVolumes.GetCount(); i++)
		{
		CString sVolume = m_LocalVolumes.GetVolume(i);

		TArray<CString> Dirs;
		fileGetFileList(fileAppend(m_LocalVolumes.GetPath(i), FILESPEC_TABLE_DIR_FILTER), FFL_FLAG_DIRECTORIES_ONLY | FFL_FLAG_RELATIVE_FILESPEC, &Dirs);

		for (j = 0; j < Dirs.GetCount(); j++)
			{
			TArray<CString> *pList = Tables.SetAt(Dirs[j]);
			pList->Insert(sVolume);
			}
		}

	//	Open all tables

	for (i = 0; i < Tables.GetCount(); i++)
		{
		CString sName = Tables.GetKey(i);

		CAeonTable *pTable = new CAeonTable;
		if (!pTable->Open(GetProcessCtx(), &m_LocalVolumes, sName, Tables[i], &sError))
			{
			Log(MSG_LOG_ERROR, strPattern("Unable to load %s: %s", sName, sError));
			delete pTable;
			continue;
			}

		m_Tables.Insert(sName, pTable);
		}

	//	Done

	return true;
	}
Exemplo n.º 2
0
CComplexStruct::CComplexStruct (const TSortMap<CString, CString> &Src)

//	CComplexStruct construtor

	{
	int i;

	for (i = 0; i < Src.GetCount(); i++)
		{
		const CString &sKey = Src.GetKey(i);
		if (!sKey.IsEmpty())
			SetElement(sKey, Src.GetValue(i));
		}
	}
Exemplo n.º 3
0
void CDesignCollection::CacheGlobalEvents (CDesignType *pType)

//	CacheGlobalEvents
//
//	Caches global events for the given type

	{
	DEBUG_TRY

	int i, j;

	const CEventHandler *pEvents;
	TSortMap<CString, SEventHandlerDesc> FullEvents;
	pType->GetEventHandlers(&pEvents, &FullEvents);
	if (pEvents)
		{
		SEventHandlerDesc Event;
		Event.pExtension = pType->GetExtension();

		for (i = 0; i < pEvents->GetCount(); i++)
			{
			CString sEvent = pEvents->GetEvent(i, &Event.pCode);

			for (j = 0; j < evtCount; j++)
				if (m_EventsCache[j]->Insert(pType, sEvent, Event))
					break;
			}
		}
	else
		{
		for (i = 0; i < FullEvents.GetCount(); i++)
			{
			CString sEvent = FullEvents.GetKey(i);
			const SEventHandlerDesc &Event = FullEvents[i];

			for (j = 0; j < evtCount; j++)
				if (m_EventsCache[j]->Insert(pType, sEvent, Event))
					break;
			}
		}

	DEBUG_CATCH
	}
Exemplo n.º 4
0
void AddTypesUsedRecursive (CUniverse &Universe, DWORD dwUNID, TSortMap<DWORD, bool> *retTypesUsed)
	{
	int i;

	//	If already added, don't bother

	if (retTypesUsed->Find(dwUNID))
		return;

	CDesignType *pType = Universe.FindDesignType(dwUNID);
	if (pType == NULL)
		return;

	retTypesUsed->SetAt(dwUNID, true);

	//	Recurse

	TSortMap<DWORD, bool> TypesUsed;
	pType->AddTypesUsed(&TypesUsed);
	for (i = 0; i < TypesUsed.GetCount(); i++)
		AddTypesUsedRecursive(Universe, TypesUsed.GetKey(i), retTypesUsed);
	}
Exemplo n.º 5
0
ALERROR OutputTypeTable (TSortMap<DWORD, STypeStats> &AllStats, int iSystemSample)
	{
	ALERROR error;
	int i, j;

	//	Output all items to a well-known file

	CTextFileLog Output(TYPE_COUNT_FILENAME);
	if (error = Output.Create(FALSE))
		{
		printf("ERROR: Unable to create output file: %s\n", TYPE_COUNT_FILENAME.GetASCIIZPointer());
		return error;
		}

	for (i = 0; i < AllStats.GetCount(); i++)
		{
		DWORD dwUNID = AllStats.GetKey(i);
		const STypeStats &Stats = AllStats[i];

		TArray<TNumberSeries<double>::SHistogramPoint> Histogram;
		Stats.PerGame.CalcHistogram(&Histogram);

		CString sLine;
		sLine = strPatternSubst("0x%x\t%d\t%d", dwUNID, (int)((Stats.PerGame.GetMean() * 1000.0) + 0.5), Histogram.GetCount());

		for (j = 0; j < Histogram.GetCount(); j++)
			sLine.Append(strPatternSubst("\t%d\t%d", Histogram[j].iValue, (int)(Histogram[j].rPercent * 100.0 + 0.5)));

		Output.LogOutput(0, sLine);
		}

	if (error = Output.Close())
		{
		printf("ERROR: Unable to create output file: %s\n", TYPE_COUNT_FILENAME.GetASCIIZPointer());
		return error;
		}

	return NOERROR;
	}
Exemplo n.º 6
0
void OutputByShipClass (SItemTableCtx &Ctx, const SItemTypeList &ItemList, bool bShowUsage)
	{
	int i, j;

	//	Make a map of ship classes for each item

	TSortMap<DWORD, TArray<CShipClass *>> ItemToShipClass;
	for (i = 0; i < g_pUniverse->GetShipClassCount(); i++)
		{
		CShipClass *pClass = g_pUniverse->GetShipClass(i);

		//	Skip non-generic ones

		if (!pClass->HasLiteralAttribute(CONSTLIT("genericClass")))
			continue;

		//	Add the list of types used by the ship

		TSortMap<DWORD, bool> TypesUsed;
		pClass->AddTypesUsed(&TypesUsed);

		//	For each item type, add it to the map

		for (j = 0; j < TypesUsed.GetCount(); j++)
			{
			CDesignType *pType = g_pUniverse->FindDesignType(TypesUsed.GetKey(j));
			if (pType && pType->GetType() == designItemType)
				{
				TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID());
				pList->Insert(pClass);
				}
			}
		}

	//	If we want to show usage, then we print each item along with the 
	//	ship classes using each item.

	if (bShowUsage)
		{
		for (i = 0; i < ItemList.GetCount(); i++)
			{
			CItemType *pType = ItemList[i];
			printf("%s\n", (LPSTR)pType->GetNounPhrase());

			TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID());
			for (j = 0; j < pList->GetCount(); j++)
				printf("\t%s\n", (LPSTR)pList->GetAt(j)->GetName());

			if (pList->GetCount() == 0)
				printf("\t(none)\n");

			printf("\n");
			}
		}

	//	Otherwise we categorize by ship class

	else
		{
		//	Now make a list of all ship classes that have our items

		SByShipClassTypeList ByShipClassTable;
		for (i = 0; i < ItemList.GetCount(); i++)
			{
			const CString &sKey = ItemList.GetKey(i);
			CItemType *pType = ItemList[i];

			//	Loop over all ship classes

			TArray<CShipClass *> *pList = ItemToShipClass.SetAt(pType->GetUNID());
			for (j = 0; j < pList->GetCount(); j++)
				{
				CString sClassName = pList->GetAt(j)->GetName();

				bool bNew;
				SShipClassEntry *pEntry = ByShipClassTable.SetAt(sClassName, &bNew);
				if (bNew)
					pEntry->sShipClassName = sClassName;

				pEntry->ItemTable.Insert(sKey, pType);
				}

			//	If no ship class

			if (pList->GetCount() == 0)
				{
				bool bNew;
				SShipClassEntry *pEntry = ByShipClassTable.SetAt(CONSTLIT("(none)"), &bNew);
				if (bNew)
					pEntry->sShipClassName = CONSTLIT("(none)");

				pEntry->ItemTable.Insert(sKey, pType);
				}
			}

		//	Now loop over all attributes

		for (i = 0; i < ByShipClassTable.GetCount(); i++)
			{
			const SShipClassEntry &Entry = ByShipClassTable[i];
			printf("%s\n\n", Entry.sShipClassName.GetASCIIZPointer());

			OutputHeader(Ctx);
			OutputTable(Ctx, Entry.ItemTable);
			printf("\n");
			}
		}
	}
Exemplo n.º 7
0
void GenerateTypeIslands (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i, j;

	bool bExcludeImages = true;

	printf("TYPE ISLANDS\n");
	printf("------------\n\n");

	//	Make a list of default types

#if 0
	g_DefaultTypes.SetAt(0x00001001, true);	//	independent sovereign
	g_DefaultTypes.SetAt(0x00001002, true);	//	Commonwealth sovereign
	g_DefaultTypes.SetAt(0x00001003, true);	//	independent sovereign
	g_DefaultTypes.SetAt(0x00001007, true);	//	ares sovereign
	g_DefaultTypes.SetAt(0x0000100c, true);	//	sung slavers sovereign
	g_DefaultTypes.SetAt(0x0000100f, true);	//	auton sovereign
	g_DefaultTypes.SetAt(0x00001011, true);	//	corporate hierarchy
	g_DefaultTypes.SetAt(0x00004027, true);	//	container of frozen supplies
	g_DefaultTypes.SetAt(0x0000402c, true);	//	pteracnium ore
	g_DefaultTypes.SetAt(0x000040ae, true);	//	helium3 reactor assembly
	g_DefaultTypes.SetAt(0x000040af, true);	//	pteracnium fuel
	g_DefaultTypes.SetAt(0x000040ca, true);	//	lancer cannon
	g_DefaultTypes.SetAt(0x000040e2, true);	//	worldship armor
	g_DefaultTypes.SetAt(0x00004100, true);	//	xenotite ore
	g_DefaultTypes.SetAt(0x00004109, true);	//	SN2500 reactor
	g_DefaultTypes.SetAt(0x00004167, true);	//	tetramite ore
	g_DefaultTypes.SetAt(0x00005004, true);	//	wreck ejecta
	g_DefaultTypes.SetAt(0x0000500c, true);	//	blast explosion 2
	g_DefaultTypes.SetAt(0x0000500d, true);	//	blast explosion 3
	g_DefaultTypes.SetAt(0x0000500e, true);	//	blast explosion 4
	g_DefaultTypes.SetAt(0x0000500f, true);	//	thermo explosion 1
	g_DefaultTypes.SetAt(0x00005011, true);	//	thermo explosion 3
	g_DefaultTypes.SetAt(0x00005012, true);	//	thermo explosion 4
	g_DefaultTypes.SetAt(0x00009004, true);	//	shield effect
	g_DefaultTypes.SetAt(0x00009007, true);	//	explosion effect
	g_DefaultTypes.SetAt(0x0000900a, true);	//	fire effect
	g_DefaultTypes.SetAt(0x0000A003, true);	//	dsAbandonedStation
	g_DefaultTypes.SetAt(0x0000a017, true);	//	dock screen?

	g_DefaultTypes.SetAt(0x001a200c, true);	//	wreck of the CSC Europa
	g_DefaultTypes.SetAt(0x001a200e, true);	//	sandstorm wreck
	g_DefaultTypes.SetAt(0x001c1002, true);	//	ares sect in Heretic
	g_DefaultTypes.SetAt(0x08020102, true);	//	huari empire sovereign
	g_DefaultTypes.SetAt(0x08040140, true);	//	gaian processor station
#endif

	//	Create a reverse index of all type dependencies

	ReverseIndexMap ReverseIndex;
	for (i = 0; i < Universe.GetDesignTypeCount(); i++)
		{
		CDesignType *pType = Universe.GetDesignType(i);

		//	Get the list of UNIDs that this type uses

		TSortMap<DWORD, bool> TypesUsed;
		pType->AddTypesUsed(&TypesUsed);
		for (j = 0; j < TypesUsed.GetCount(); j++)
			{
			CDesignType *pRequired = Universe.FindDesignType(TypesUsed.GetKey(j));
			if (pRequired == NULL)
				continue;

			//	Add to reverse index

			TArray<DWORD> *pList = ReverseIndex.SetAt(pRequired->GetUNID());
			pList->Insert(pType->GetUNID());
			}
		}

	//	We create a list of islands. In each island, all the types refer to
	//	each other and don't refer to types on any other island.

	TArray<IslandMap> AllIslands;

	//	Loop over all types and add them to an island.

	for (i = 0; i < Universe.GetDesignTypeCount(); i++)
		{
		CDesignType *pType = Universe.GetDesignType(i);

		//	Exclude images

		if (bExcludeImages && pType->GetType() == designImage)
			continue;

		if (pType->GetType() == designShipTable)
			continue;

		//	Exclude default types

		if (g_DefaultTypes.Find(pType->GetUNID()))
			continue;

		//	If this type is already on one of the islands, then we skip it.

#if 0
		bool bFound = false;
		for (j = 0; j < AllIslands.GetCount(); j++)
			if (AllIslands[j].Find(pType->GetUNID()))
				{
				bFound = true;
				break;
				}

		if (bFound)
			continue;
#endif 

		//	Since this type is not on any island, we add start a new island and
		//	add all related types to it.

		IslandMap *pIsland = AllIslands.Insert();
		AddTypeToIsland(Universe, ReverseIndex, pIsland, pType);

		//	Print

		printf("ISLAND %s\n", (char *)GetTypeDesc(pType));

		for (j = 0; j < pIsland->GetCount(); j++)
			{
			CDesignType *pType = Universe.FindDesignType(pIsland->GetKey(j));
			if (pType == NULL)
				continue;

			printf("%s\n", (char *)GetTypeDesc(pType));
			}

		printf("\n");
		}
	}
Exemplo n.º 8
0
void GenerateTypeDependencies (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i, j;

	bool bRecursive = pCmdLine->GetAttributeBool(CONSTLIT("recursive"));
	bool bReverse = pCmdLine->GetAttributeBool(CONSTLIT("reverse"));

	//	Create a reverse index of all type dependencies

	TSortMap<DWORD, TArray<DWORD> > ReverseIndex;

	//	Types and what they use

	if (!bReverse)
		{
		printf("TYPES AND WHAT THEY USE\n");
		printf("-----------------------\n\n");
		}

	for (i = 0; i < Universe.GetDesignTypeCount(); i++)
		{
		CDesignType *pType = Universe.GetDesignType(i);

		if (!bReverse)
			printf("%s\n", (char *)GetTypeDesc(pType));

		//	Get the list of UNIDs that this type uses

		TSortMap<DWORD, bool> TypesUsed;
		if (bRecursive)
			AddTypesUsedRecursive(Universe, pType->GetUNID(), &TypesUsed);
		else
			pType->AddTypesUsed(&TypesUsed);

		//	Output the list

		for (j = 0; j < TypesUsed.GetCount(); j++)
			{
			CDesignType *pRequired = Universe.FindDesignType(TypesUsed.GetKey(j));
			if (pRequired == NULL)
				continue;

			if (!bReverse)
				printf("\t%s\n", (char *)GetTypeDesc(pRequired));

			//	Add to reverse index

			TArray<DWORD> *pList = ReverseIndex.SetAt(pRequired->GetUNID());
			pList->Insert(pType->GetUNID());
			}
		}

	//	Types and what depends on them

	if (bReverse)
		{
		printf("\nTYPES AND WHAT USES THEM\n");
		printf(  "------------------------\n\n");

		for (i = 0; i < ReverseIndex.GetCount(); i++)
			{
			CDesignType *pType = Universe.FindDesignType(ReverseIndex.GetKey(i));
			if (pType == NULL)
				continue;

			printf("%s\n", (char *)GetTypeDesc(pType));

			TArray<DWORD> &List = ReverseIndex.GetValue(i);
			for (j = 0; j < List.GetCount(); j++)
				{
				CDesignType *pRequiredBy = Universe.FindDesignType(List[j]);
				if (pRequiredBy)
					printf("\t%s\n", (char *)GetTypeDesc(pRequiredBy));
				}
			}
		}
	}
Exemplo n.º 9
0
void GenerateTopology (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i, j, k;

	int iCount = pCmdLine->GetAttributeIntegerBounded(COUNT_SWITCH, 1, -1, 1);

	STopologyStats Stats;

	for (k = 0; k < iCount; k++)
		{
		if (iCount > 1)
			printf("sample %d", k+1);

		TSortMap<CString, SNodeInfo> NodeData;
		TSortMap<CString, int> AttribCount;

		//	Initialize the topology

		CString sError;
		Universe.GetFirstTopologyNode();

		//	Loop over all nodes

		for (i = 0; i < Universe.GetTopologyNodeCount(); i++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(i);

			SNodeInfo *pNewNode = NodeData.Insert(pNode->GetID());
			pNewNode->sID = pNode->GetID();
			pNewNode->sName = pNode->GetSystemName();
			pNewNode->dwSystemUNID = pNode->GetSystemDescUNID();
			pNewNode->sAttribs = pNode->GetAttributes();

			//	Add the attributes in this node to the list of 
			//	attributes for this try.

			TArray<CString> Attribs;
			ParseAttributes(pNewNode->sAttribs, &Attribs);
			for (j = 0; j < Attribs.GetCount(); j++)
				{
				int *pCount = AttribCount.GetAt(Attribs[j]);
				if (pCount == NULL)
					{
					pCount = AttribCount.Insert(Attribs[j]);
					*pCount = 0;
					}

				*pCount = (*pCount) + 1;
				}
			}

		//	Compute topology stats
		//	Add the node count for this try

		Stats.NodeCount.Insert(NodeData.GetCount());

		//	Loop over all attributes that we know about. If one doesn't
		//	exist in this try, then we set its min to 0

		if (k > 0)
			{
			for (i = 0; i < Stats.Attribs.GetCount(); i++)
				{
				if (AttribCount.GetAt(Stats.Attribs.GetKey(i)) == NULL)
					Stats.Attribs[i].SetMin(0);
				}
			}

		//	Loop over all attributes in this try and add them to the stats

		SStat *pAttribStat;
		for (i = 0; i < AttribCount.GetCount(); i++)
			{
			//	If we have some attributes that no other try had, then
			//	that means that the minimum value is 0.

			if (pAttribStat = Stats.Attribs.GetAt(AttribCount.GetKey(i)))
				pAttribStat->Insert(AttribCount[i]);
			else
				{
				pAttribStat = Stats.Attribs.Insert(AttribCount.GetKey(i));
				pAttribStat->Insert(AttribCount[i]);
				if (k > 0)
					pAttribStat->SetMin(0);
				}
			}

		//	Output all the nodes

		if (iCount == 1)
			{
			printf("Node\tSystemType\tName\tStargates\tAttributes\n");
			for (i = 0; i < NodeData.GetCount(); i++)
				{
				SNodeInfo *pNode = &NodeData.GetValue(i);
				printf("%s\t%08x\t%s\t%d\t%s\n",
						pNode->sID.GetASCIIZPointer(),
						pNode->dwSystemUNID,
						pNode->sName.GetASCIIZPointer(),
						pNode->Stargates.GetCount(),
						pNode->sAttribs.GetASCIIZPointer());
				}
			}
		else
			{
			Universe.Reinit();
			printf("\n");
			}
		}

	//	Output stats

	if (iCount > 0)
		{
		printf("\n");
		printf("STATS\n\n");
		Stats.NodeCount.Print(CONSTLIT("Nodes"), iCount, Stats.NodeCount.GetAverage(iCount));
		printf("\n");

		printf("ATTRIBS\n\n");
		for (i = 0; i < Stats.Attribs.GetCount(); i++)
			Stats.Attribs[i].Print(Stats.Attribs.GetKey(i), iCount, Stats.NodeCount.GetAverage(iCount));
		printf("\n");
		}
	}
Exemplo n.º 10
0
void GenerateEncounterFrequency (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	enum ETypes
		{
		outputFreq,
		outputFillLocations,
		};

	int i, j;

	//	Options

	int iSystemSample = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);
	bool bLogo = !pCmdLine->GetAttributeBool(CONSTLIT("noLogo"));
	bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all"));

	bool bRawData = pCmdLine->GetAttributeBool(CONSTLIT("rawData"));
	
	ETypes iType;
	if (pCmdLine->GetAttributeBool(CONSTLIT("fillLocations")))
		iType = outputFillLocations;
	else
		iType = outputFreq;

	//	Additional columns

	TArray<CString> Cols;
	for (i = 0; i < pCmdLine->GetAttributeCount(); i++)
		{
		CString sAttrib = pCmdLine->GetAttributeName(i);

		if (!IsMainCommandParam(sAttrib)
				&& !strEquals(sAttrib, CONSTLIT("count"))
				&& !strEquals(sAttrib, CONSTLIT("fillLocations"))
				&& !strEquals(sAttrib, CONSTLIT("rawData"))
				&& !strEquals(sAttrib, CONSTLIT("encounterfreq")))
			{
			CString sValue = pCmdLine->GetAttribute(i);
			
			if (!strEquals(sValue, CONSTLIT("true")))
				Cols.Insert(strPatternSubst(CONSTLIT("%s:%s"), sAttrib, sValue));
			else
				Cols.Insert(sAttrib);
			}
		}

	//	Generate systems for multiple games

	CSystemCreateStats Stats;
	for (i = 0; i < iSystemSample; i++)
		{
		if (bLogo)
			printf("pass %d...\n", i+1);

		//	Initialize the game

		CString sError;
		if (Universe.InitGame(0, &sError) != NOERROR)
			{
			printf("%s\n", sError.GetASCIIZPointer());
			return;
			}

		for (j = 0; j < Universe.GetTopologyNodeCount(); j++)
			{
			CTopologyNode *pNode = Universe.GetTopologyNode(j);
			if (pNode->IsEndGame())
				continue;

			//	Create the system

			CSystem *pSystem;
			if (Universe.CreateStarSystem(pNode, &pSystem, NULL, &Stats) != NOERROR)
				{
				printf("ERROR: Unable to create star system.\n");
				return;
				}

			//	Done with old system

			Universe.DestroySystem(pSystem);
			}

		Universe.Reinit();
		}

	//	Output based on type

	if (iType == outputFreq)
		{
		//	Generate a table for each encounter

		TSortMap<CStationType *, SEncounterFreqEntry> EncounterFreq;
		for (i = 0; i < Stats.GetEncounterTableCount(); i++)
			{
			const CSystemCreateStats::SEncounterTable &Table = Stats.GetEncounterTable(i);

			//	Skip if only planets and asteroids

			if (!Table.bHasStation && !bAll)
				continue;

			//	For each entry in the table, add to the frequency table

			for (j = 0; j < Table.Table.GetCount(); j++)
				{
				CStationType *pEncounterType = Table.Table.GetAt(j);
				int iChance = Table.Table.GetChance(j);

				SEncounterFreqEntry *pEntry = EncounterFreq.SetAt(pEncounterType);
				pEntry->iCount += Table.iCount;
				pEntry->iTotalChance += Table.iCount * iChance;

				if (pEntry->pMaxTable == NULL || iChance > pEntry->iMaxChance)
					{
					pEntry->pMaxTable = &Table;
					pEntry->iMaxChance = iChance;
					}

				if (pEntry->pMinTable == NULL || iChance < pEntry->iMinChance)
					{
					pEntry->pMinTable = &Table;
					pEntry->iMinChance = iChance;
					}
				}
			}

		//	Output encounter frequency distribution

		printf("Level\tCategory\tEncounter\tTotal Chances\tAverage Chance\tMin Chance\tMax Chance");
		for (i = 0; i < Cols.GetCount(); i++)
			printf("\t%s", Cols[i].GetASCIIZPointer());
		printf("\n");

		for (i = 0; i < EncounterFreq.GetCount(); i++)
			{
			CStationType *pEncounterType = EncounterFreq.GetKey(i);
			int iAveWhole = EncounterFreq[i].iTotalChance / EncounterFreq[i].iCount;
			int iAveFrac = 1000 * (EncounterFreq[i].iTotalChance % EncounterFreq[i].iCount) / EncounterFreq[i].iCount;

			printf("%d\t%s\t%s\t%d\t%d.%03d\t%d\t%d",
					pEncounterType->GetLevel(),
					pEncounterType->GetDataField(CONSTLIT("category")).GetASCIIZPointer(),
					pEncounterType->GetName().GetASCIIZPointer(),
					EncounterFreq[i].iCount,
					iAveWhole,
					iAveFrac,
					EncounterFreq[i].iMinChance,
					EncounterFreq[i].iMaxChance);

			for (j = 0; j < Cols.GetCount(); j++)
				{
				CString sValue = pEncounterType->GetDataField(Cols[j]);
				printf("\t%s", sValue.GetASCIIZPointer());
				}

			printf("\n");
			}

		//	Output raw data

		if (bRawData)
			{
			//	Loop over stats and output tables

			for (i = 0; i < Stats.GetEncounterTableCount(); i++)
				{
				const CSystemCreateStats::SEncounterTable &Table = Stats.GetEncounterTable(i);

				//	Skip if only planets and asteroids

				if (!Table.bHasStation && !bAll)
					continue;

				//	Header

				printf("LEVEL %d (%d location%s)\nSystem Type: %08x\nStations: %s\n", 
						Table.iLevel,
						Table.iCount,
						(Table.iCount == 1 ? "" : "s"),
						Table.pSystemType->GetUNID(),
						Table.sStationCriteria.GetASCIIZPointer());

				//	Location attributes

				printf("Location: ");
				for (j = 0; j < Table.LabelAttribs.GetCount(); j++)
					{
					if (j != 0)
						printf(", ");
					printf(Table.LabelAttribs[j].GetASCIIZPointer());
					}
				printf("\n");

				//	Entries

				for (j = 0; j < Table.Table.GetCount(); j++)
					printf("%s\t%d\n", Table.Table.GetAt(j)->GetName().GetASCIIZPointer(), Table.Table.GetChance(j));

				printf("\n");
				}
			}
		}
	else if (iType == outputFillLocations)
		{
		printf("Level\tSystem\tEncounter\tChance\n");

		for (i = 0; i < Stats.GetFillLocationsTableCount(); i++)
			{
			const CSystemCreateStats::SFillLocationsTable &Entry = Stats.GetFillLocationsTable(i);

			for (j = 0; j < Entry.Table.GetCount(); j++)
				{
				int iPercent = (int)(1000.0 * Entry.Table.GetChance(j) / (Metric)Entry.Table.GetTotalChance());

				printf("%d\t%s\t%s\t%d.%d\n",
						Entry.iLevel,
						Entry.sSystemName.GetASCIIZPointer(),
						Entry.Table[j]->GetName().GetASCIIZPointer(), 
						iPercent / 10,
						iPercent % 10);
				}
			}
		}
	}