예제 #1
0
void SortTable (SItemTableCtx &Ctx, const TArray<CItemType *> &List, SItemTypeList *retSorted)
	{
	int i;

	//	Loop over all items that match and add them to
	//	a sorted table.

	retSorted->DeleteAll();
	for (i = 0; i < List.GetCount(); i++)
		{
		CItemType *pType = List[i];

		//	Add with sort key

		char szBuffer[1024];
		wsprintf(szBuffer, "%02d%s%02d%s", 
				pType->GetLevel(),
				g_szTypeCode[GetItemType(pType)], 
				GetItemFreq(pType), 
				pType->GetNounPhrase().GetASCIIZPointer());
		retSorted->Insert(CString(szBuffer), pType);
		}
	}
bool CWeaponBenchmarkCtx::InitArmorTable (void)

//  InitArmorTable
//
//  Initializes the armor table, which lists armor by level.

    {
    int i;

    //  If we've already initialized the table, then nothing to do.

    if (m_ArmorTable.GetCount() != 0)
        return true;

    //  Create table

    for (i = 0; i < g_pUniverse->GetItemTypeCount(); i++)
        {
        CItemType *pType = g_pUniverse->GetItemType(i);

        //  Skip non-armor

        if (!pType->IsArmor()
                || pType->IsVirtual())
            continue;

        //  Add to our list, indexed by level.

        TArray<CItemType *> *pTable = m_ArmorTable.SetAt(pType->GetLevel());
        pTable->Insert(pType);
        }

    //  Done

    return true;
    }
예제 #3
0
void GenerateArmorTable (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i;

	printf("ARMOR TABLE\n\n");

	printf("Level\tArmor\tCost\tWeight\tHP\tLasr\tImpc\tPart\tBlst\tIon\tThrm\tPosi\tPlsm\tAnti\tNano\tGrav\tSing\tDacd\tDstl\tDlgt\tDfir\n");
	for (i = 0; i < Universe.GetItemTypeCount(); i++)
		{
		CItemType *pItem = Universe.GetItemType(i);
		CArmorClass *pArmor = pItem->GetArmorClass();
		if (pArmor == NULL)
			continue;

		CItem Item(pItem, 1);
		CString sName = pItem->GetName(NULL);
		int iHP = pArmor->GetMaxHP(CItemCtx(&Item));

		printf("%d\t%s\t%d\t%d\t%d\t", 
				pItem->GetLevel(), 
				sName.GetASCIIZPointer(), 
				Item.GetValue(true), 
				Item.GetMassKg(),
				iHP);

		//	For each damage type, compute the adjusted hit points of the armor

		int iDamage;
		for (iDamage = damageLaser; iDamage < damageCount; iDamage++)
			{
			printf("%d", pArmor->GetDamageAdj(CItemCtx(Item), (DamageTypes)iDamage));
			if (iDamage != damageCount - 1)
				printf("\t");
			}

		printf("\n");
		}

	printf("ARMOR TABLE DAMAGE ADJUSTMENTS\n\n");

	printf("Level\tArmor\tHP\tLasr\tImpc\tPart\tBlst\tIon\tThrm\tPosi\tPlsm\tAnti\tNano\tGrav\tSing\tDacd\tDstl\tDlgt\tDfir\n");
	for (i = 0; i < Universe.GetItemTypeCount(); i++)
		{
		CItemType *pItem = Universe.GetItemType(i);
		CArmorClass *pArmor = pItem->GetArmorClass();
		if (pArmor == NULL)
			continue;

		CString sName = pItem->GetName(NULL);
		CItem Item(pItem, 1);
		int iHP = pArmor->GetMaxHP(CItemCtx(&Item));

		printf("%d\t%s\t%d\t", 
				pItem->GetLevel(), 
				sName.GetASCIIZPointer(), 
				iHP);

		//	For each damage type, compute the adjusted hit points of the armor

		int iDamage;
		for (iDamage = damageLaser; iDamage < damageCount; iDamage++)
			{
			int iAdj = pArmor->GetDamageAdj(CItemCtx(Item), (DamageTypes)iDamage);
			if (iAdj == 0)
				printf("----");
			else
				printf("%d", iHP * 100 / iAdj);

			if (iDamage != damageCount - 1)
				printf("\t");
			}

		printf("\n");
		}
	}
예제 #4
0
bool CSpaceObject::GetRefuelItemAndPrice (CSpaceObject *pObjToRefuel, CItemType **retpItemType, int *retiPrice)

//	GetRefuelItemAndPrice
//
//	Returns the appropriate item to use for refueling (based on the trading
//	directives).

	{
	int i;

	if (IsAbandoned())
		return false;

	//	See if we have an override

	CTradingDesc *pTradeOverride = GetTradeDescOverride();
	if (pTradeOverride && pTradeOverride->GetRefuelItemAndPrice(this, pObjToRefuel, 0, retpItemType, retiPrice))
		return true;

	//	Otherwise, ask our design type

	CDesignType *pType = GetType();
	if (pType == NULL)
		return false;

	CTradingDesc *pTrade = pType->GetTradingDesc();
	if (pTrade && pTrade->GetRefuelItemAndPrice(this, pObjToRefuel, 0, retpItemType, retiPrice))
		return true;

	//	For compatibility, any ship prior to version 23 has a default.
	//	[For API Version 23 and above, ships must have a <Trade> descriptor.]

	if (pType->GetAPIVersion() < 23
			&& pType->GetType() == designShipClass)
		{
		//	Get the ship

		CShip *pShipToRefuel = pObjToRefuel->AsShip();
		if (pShipToRefuel == NULL)
			return false;

		//	Find the highest-level item that can be used by the ship

		int iBestLevel = 0;
		int iBestPrice = 0;
		CItemType *pBestItem = NULL;

		for (i = 0; i < g_pUniverse->GetItemTypeCount(); i++)
			{
			CItemType *pType = g_pUniverse->GetItemType(i);
			CItem Item(pType, 1);

			if (pShipToRefuel->IsFuelCompatible(Item))
				{
				if (pBestItem == NULL || pType->GetLevel() > iBestPrice)
					{
					//	Compute the price, because if we don't sell it, then we
					//	skip it.
					//
					//	NOTE: Unlike selling, we allow 0 prices because some 
					//	stations give fuel for free.

					int iPrice = CTradingDesc::CalcPriceForService(serviceRefuel, this, Item, 1, 0);
					if (iPrice >= 0)
						{
						pBestItem = pType;
						iBestLevel = pType->GetLevel();
						iBestPrice = iPrice;
						}
					}
				}
			}

		if (pBestItem == NULL)
			return false;

		//	Done

		if (retpItemType)
			*retpItemType = pBestItem;

		if (retiPrice)
			*retiPrice = iBestPrice;

		return true;
		}

	//	Otherwise, we do not refuel

	return false;
	}
예제 #5
0
void GenerateShieldStats (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	int i;

	CString sUNID = pCmdLine->GetAttribute(CONSTLIT("unid"));
	DWORD dwUNID = strToInt(sUNID, 0, NULL);
	CItemType *pItem = Universe.FindItemType(dwUNID);
	if (pItem == NULL)
		{
		CItemCriteria Crit;
		CItem::InitCriteriaAll(&Crit);
		CItem Item = CItem::CreateItemByName(sUNID, Crit);
		pItem = Item.GetType();

		if (pItem == NULL)
			{
			printf("ERROR: Unknown item '%s'\n", sUNID.GetASCIIZPointer());
			return;
			}
		}

	if (pItem->GetCategory() != itemcatShields)
		{
		printf("ERROR: Item '%s' is not a shield generator\n", pItem->GetNounPhrase().GetASCIIZPointer());
		return;
		}

	bool bVerbose = pCmdLine->GetAttributeBool(CONSTLIT("verbose"));
	bool bEval = pCmdLine->GetAttributeBool(CONSTLIT("eval"));

	//	Get the stats for the shield

	Metric rHP = (Metric)pItem->GetDataFieldInteger(FIELD_HP);
	Metric rHPRegenPerTick = pItem->GetDataFieldInteger(FIELD_REGEN) / 1000.0;

	int iDamageAdj[damageCount];
	CString sDamageAdj = pItem->GetDataField(CONSTLIT("damageAdj"));
	char *pPos = sDamageAdj.GetASCIIZPointer();
	int iCount = 0;
	while (iCount < damageCount)
		{
		iDamageAdj[iCount] = strParseInt(pPos, 0, &pPos, NULL);
		if (*pPos != '\0')
			pPos++;
		iCount++;
		}

	//	Print header

	printf("%s\n\n", pItem->GetNounPhrase().GetASCIIZPointer());

	//	Loop over all weapons and sort them by level and then name

	CSymbolTable List(FALSE, TRUE);
	for (i = 0; i < Universe.GetItemTypeCount(); i++)
		{
		CItemType *pWeapon = Universe.GetItemType(i);
		if (pWeapon->GetCategory() != itemcatWeapon)
			continue;

		CString sLevel = (pWeapon->GetLevel() < 10 ? strPatternSubst(CONSTLIT("0%d"), pWeapon->GetLevel()) : strFromInt(pWeapon->GetLevel(), FALSE));
		CString sSortName = strPatternSubst(CONSTLIT("%s%s"), sLevel, pWeapon->GetNounPhrase());
		List.AddEntry(sSortName, (CObject *)pWeapon);
		}

	//	Loop over sorted list and output data

	for (i = 0; i < List.GetCount(); i++)
		{
		CItemType *pWeapon = (CItemType *)List.GetValue(i);

		//	Get the data for the weapon

		int iFireDelay = pWeapon->GetDataFieldInteger(CONSTLIT("fireDelay"));
		Metric rAverageDamage = pWeapon->GetDataFieldInteger(CONSTLIT("averageDamage")) / 1000.0;
		int iDamageType = pWeapon->GetDataFieldInteger(CONSTLIT("damageType"));
		if (iDamageType < 0 || iDamageType >= damageCount)
			iDamageType = 0;

		//	Adjust damage for type

		rAverageDamage = rAverageDamage * (iDamageAdj[iDamageType] / 100.0);
		if (rAverageDamage < 1.0)
			rAverageDamage = 0.0;

		//	Calculate how many shots it would take to pierce through the shields

		char szBuffer[256];
		Metric rShotsToDeplete;
		Metric rRegenPerShot = rHPRegenPerTick * (Metric)iFireDelay;
		if (rRegenPerShot >= rAverageDamage)
			{
			rShotsToDeplete = 1000000.0;
			lstrcpy(szBuffer, "ineffective");
			}
		else
			{
			Metric rDrainPerShot = rAverageDamage - rRegenPerShot;
			rShotsToDeplete = rHP / rDrainPerShot;
			sprintf(szBuffer, "%.2f", rShotsToDeplete);
			}

		//	See if this weapon is overpowered or underpowered

		char szEval[256];
		if (bEval)
			{
			lstrcpy(szEval, "\t");
			if (pWeapon->GetLevel() < pItem->GetLevel())
				{
				if (rShotsToDeplete <= 10.0)
					lstrcpy(szEval, "\tOVERpowered");
				}
			else
				{
				if (rShotsToDeplete > 20.0)
					lstrcpy(szEval, "\tUNDERpowered");
				}
			}
		else
			lstrcpy(szEval, "");

		//	Print table

		if (bVerbose)
			{
			printf("%s\t%s\t%s\t(%d ticks; %.2f damage; %.2f regen/shot)%s\n",
					RomanNumeral(pWeapon->GetLevel()),
					pWeapon->GetNounPhrase().GetASCIIZPointer(),
					szBuffer,
					iFireDelay,
					rAverageDamage,
					rRegenPerShot,
					szEval);
			}
		else
			{
			printf("%s\t%s\t%s%s\n",
					RomanNumeral(pWeapon->GetLevel()),
					pWeapon->GetNounPhrase().GetASCIIZPointer(),
					szBuffer,
					szEval);
			}
		}
	}
예제 #6
0
void CRandomItems::InitTable (void)

//	InitTable
//
//	Initializes the m_Table array.
//
//	We assume that m_Criteria, m_sLevelFrequency, m_iLevel, and m_iLevelCurve are properly initialized.

	{
	int i;

	//	Start by allocating an array large enough to hold
	//	all item types in the universe

	ItemEntryStruct *pTable = new ItemEntryStruct [g_pUniverse->GetItemTypeCount()];
	int iTableSize = 0;

	//	Figure out if we should use level curves or level frequency

	bool bUseLevelFrequency = !m_sLevelFrequency.IsBlank();

	//	Iterate over every item type and add it to the table if
	//	it matches the given criteria

	for (i = 0; i < g_pUniverse->GetItemTypeCount(); i++)
		{
		CItemType *pType = g_pUniverse->GetItemType(i);
		CItem Item(pType, 1);

		//	Skip if the item doesn't match the categories

		if (!Item.MatchesCriteria(m_Criteria))
			continue;

		//	Skip if this item is not found randomly

		if (pType->GetFrequency() == ftNotRandom)
			continue;

		//	Adjust score based on level, either the level curve
		//	or the level frequency string.

		int iScore;
		if (bUseLevelFrequency)
			{
			iScore = 1000 * GetFrequencyByLevel(m_sLevelFrequency, pType->GetLevel()) / ftCommon;
			}
		else
			{
			//	Skip if the item is not within the level curve

			if ((pType->GetLevel() < m_iLevel - m_iLevelCurve)
					|| (pType->GetLevel() > m_iLevel + m_iLevelCurve))
				continue;

			//	If we get this far then the item perfectly matches
			//	and we need to add it to our table. First, however, we need
			//	to calculate a score.
			//
			//	The score is number that represents how common the item
			//	is in the table. Later we normalize the score to be a probability

			int iLevelDelta = pType->GetLevel() - m_iLevel;
			switch (iLevelDelta)
				{
				case 0:
					iScore = 1000;
					break;

				case 1:
				case -1:
					iScore = 500;
					break;

				case 2:
				case -2:
					iScore = 200;
					break;

				default:
					iScore = 50;
				}
			}

		//	Adjust score based on item frequency

		iScore = iScore * pType->GetFrequency() * 10 / (ftCommon * 10);

		//	If we have a score of 0 then we skip this item

		if (iScore == 0)
			continue;

		//	Add the item to the table

		pTable[iTableSize].pType = pType;
		pTable[iTableSize].iChance = iScore;
		iTableSize++;
		}

	//	We must have items

	if (iTableSize == 0)
		{
		m_iCount = 0;
		m_Table = NULL;
		return;
		}

	//	Add up the total score of all items

	int iTotalScore = 0;
	for (i = 0; i < iTableSize; i++)
		iTotalScore += pTable[i].iChance;

	//	Compute the chance

	int iTotalChance = 0;
	for (i = 0; i < iTableSize; i++)
		{
		int iScore = pTable[i].iChance;
		pTable[i].iChance = (iScore * 1000) / iTotalScore;
		pTable[i].iRemainder = (iScore * 1000) % iTotalScore;

		iTotalChance += pTable[i].iChance;
		}

	//	Distribute the remaining chance points

	while (iTotalChance < 1000)
		{
		//	Look for the entry with the biggest remainder

		int iBestRemainder = 0;
		int iBestEntry = -1;

		for (i = 0; i < iTableSize; i++)
			if (pTable[i].iRemainder > iBestRemainder)
				{
				iBestRemainder = pTable[i].iRemainder;
				iBestEntry = i;
				}

		pTable[iBestEntry].iChance++;
		pTable[iBestEntry].iRemainder = 0;
		iTotalChance++;
		}

	//	Count the number of entries that we've got

	m_iCount = 0;
	for (i = 0; i < iTableSize; i++)
		if (pTable[i].iChance > 0)
			m_iCount++;

	//	Now loop over the entire table and add it to the 
	//	random entry generator

	m_Table = new SEntry [m_iCount];
	int j = 0;
	for (i = 0; i < iTableSize; i++)
		if (pTable[i].iChance > 0)
			{
			m_Table[j].pType = pTable[i].pType;
			m_Table[j].iProbability = pTable[i].iChance;
			j++;
			}

	//	Done

	delete [] pTable;
	}
예제 #7
0
void CUIHelper::CreateClassInfoItem (const CItem &Item, int x, int y, int cxWidth, DWORD dwOptions, const CString &sExtraDesc, int *retcyHeight, IAnimatron **retpInfo) const

//	CreateClassInfoItem
//
//	Creates an item info animation

	{
	const CVisualPalette &VI = m_HI.GetVisuals();
	const CG16bitFont &MediumFont = VI.GetFont(fontMedium);
	const CG16bitFont &MediumBoldFont = VI.GetFont(fontMediumBold);
	const CG16bitFont &SubTitleFont = VI.GetFont(fontSubTitle);

	//	Handle some edge conditions

	CItemType *pType = Item.GetType();
	if (pType == NULL)
		{
		if (retcyHeight)
			*retcyHeight = 0;

		CAniSequencer::Create(CVector(x, y), (CAniSequencer **)retpInfo);
		return;
		}

	//	Figure out some dimensions and metrics. Everything is relative to x, y.

	bool bRightAlign = ((dwOptions & OPTION_ITEM_RIGHT_ALIGN) ? true : false);
	int cxIcon = SMALL_ICON_WIDTH;
	int cyIcon = SMALL_ICON_HEIGHT;
	int xIcon = (bRightAlign ? -cxIcon : 0);
	int yIcon = 0;

	int cxText = cxWidth - (cxIcon + ITEM_INFO_SPACING_HORZ);
	int xText = (bRightAlign ? -cxWidth : cxIcon + ITEM_INFO_SPACING_HORZ);
	int yText = 0;

	//	Create a sequencer to hold all the controls

	CAniSequencer *pRoot;
	CAniSequencer::Create(CVector(x, y), &pRoot);

	//	Create a small item icon

	const CObjectImageArray &Image = pType->GetImage();
	RECT rcImage = Image.GetImageRect();
	if (!Image.IsEmpty())
		{
		CG16bitImage *pIcon = new CG16bitImage;
		pIcon->CreateFromImageTransformed(Image.GetImage(), 
				rcImage.left, 
				rcImage.top, 
				RectWidth(rcImage), 
				RectHeight(rcImage), 
				(Metric)SMALL_ICON_WIDTH / RectWidth(rcImage),
				(Metric)SMALL_ICON_HEIGHT / RectHeight(rcImage),
				0.0);

		IAnimatron *pImageFrame = new CAniRect;
		pImageFrame->SetPropertyVector(PROP_POSITION, CVector(xIcon, yIcon));
		pImageFrame->SetPropertyVector(PROP_SCALE, CVector(SMALL_ICON_WIDTH, SMALL_ICON_HEIGHT));
		pImageFrame->SetFillMethod(new CAniImageFill(pIcon, true));

		pRoot->AddTrack(pImageFrame, 0);
		}

	//	Create text

	int cyText = 0;

	IAnimatron *pName = new CAniText;
	pName->SetPropertyVector(PROP_POSITION, CVector(xText, yText + cyText));
	pName->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000));
	pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput));
	pName->SetPropertyFont(PROP_FONT, &MediumBoldFont);
	pName->SetPropertyString(PROP_TEXT, pType->GetNounPhrase(nounActual));
	if (bRightAlign)
		pName->SetPropertyString(PROP_TEXT_ALIGN_HORZ, ALIGN_RIGHT);

	pRoot->AddTrack(pName, 0);
	cyText += MediumBoldFont.GetHeight();

	//	Add the damage type adjustment

	CItemDataAnimatron *pDamageDesc = new CItemDataAnimatron(VI, Item);
	if (!pDamageDesc->IsEmpty())
		{
		pDamageDesc->SetPropertyVector(PROP_POSITION, CVector(xText, yText + cyText));
		pDamageDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000));
		if (bRightAlign)
			pDamageDesc->SetPropertyString(PROP_TEXT_ALIGN_HORZ, ALIGN_RIGHT);

		pRoot->AddTrack(pDamageDesc, 0);

		RECT rcRect;
		pDamageDesc->GetSpacingRect(&rcRect);
		cyText += RectHeight(rcRect);
		}
	else
		delete pDamageDesc;

	//	Add the reference text

	CItemCtx ItemCtx;
	CString sRef = pType->GetReference(ItemCtx, -1, CItemType::FLAG_ACTUAL_ITEM);
	if (sRef.IsBlank())
		sRef = strPatternSubst(CONSTLIT("Level %s%s"), strLevel(pType->GetLevel()), sExtraDesc);
	else
		sRef = strPatternSubst(CONSTLIT("Level %s — %s%s"), strLevel(pType->GetLevel()), sRef, sExtraDesc);

	IAnimatron *pRef = new CAniText;
	pRef->SetPropertyVector(PROP_POSITION, CVector(xText, yText + cyText));
	pRef->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000));
	pRef->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel));
	pRef->SetPropertyFont(PROP_FONT, &MediumFont);
	pRef->SetPropertyString(PROP_TEXT, sRef);
	if (bRightAlign)
		pRef->SetPropertyString(PROP_TEXT_ALIGN_HORZ, ALIGN_RIGHT);

	pRoot->AddTrack(pRef, 0);

	RECT rcRef;
	pRef->GetSpacingRect(&rcRef);
	cyText += RectHeight(rcRef);

	//	Done

	if (retcyHeight)
		*retcyHeight = Max(cyText, SMALL_ICON_HEIGHT);

	*retpInfo = pRoot;
	}
예제 #8
0
void GenerateItemTable (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	ALERROR error;
	int i, j;

	//	Compute the criteria

	CItemCriteria Crit;
	CString sCriteria;
	if (pCmdLine->FindAttribute(CRITERIA_ATTRIB, &sCriteria))
		CItem::ParseCriteria(sCriteria, &Crit);
	else
		CItem::InitCriteriaAll(&Crit);

	//	Generate a table

	CSymbolTable Table(FALSE, TRUE);

	//	Loop over all items that match and add them to
	//	a sorted table.

	for (j = 0; j < Universe.GetItemTypeCount(); j++)
		{
		CItemType *pType = Universe.GetItemType(j);
		CItem Item(pType, 1);

		if (!Item.MatchesCriteria(Crit))
			continue;

		//	Figure out the sort order

		char szBuffer[1024];
		wsprintf(szBuffer, "%02d%s%02d%s", 
				pType->GetLevel(),
				g_szTypeCode[GetItemType(pType)], 
				GetItemFreq(pType), 
				pType->GetNounPhrase().GetASCIIZPointer());
		Table.AddEntry(CString(szBuffer), (CObject *)pType);
		}

	//	If we need to output total count, then load the table

	CSymbolTable TotalCount(TRUE, TRUE);
	if (pCmdLine->GetAttributeBool(FIELD_TOTAL_COUNT))
		{
		if (error = LoadTotalCount(TOTAL_COUNT_FILENAME, TotalCount))
			return;
		}

	//	If we've got any entries in the table, output now

	if (Table.GetCount())
		{
		//	Generate a list of columns to display

		CStringArray Cols;
		Cols.AppendString(FIELD_LEVEL);
		Cols.AppendString(FIELD_TYPE);
		Cols.AppendString(FIELD_FREQUENCY);
		Cols.AppendString(FIELD_NAME);

		//	More columns from command-line

		if (pCmdLine->GetAttributeBool(FIELD_AVERAGE_COUNT))
			Cols.AppendString(FIELD_AVERAGE_COUNT);
		if (pCmdLine->GetAttributeBool(FIELD_BALANCE))
			Cols.AppendString(FIELD_BALANCE);
		if (pCmdLine->GetAttributeBool(FIELD_COST))
			Cols.AppendString(FIELD_COST);
		if (pCmdLine->GetAttributeBool(FIELD_INSTALL_COST))
			Cols.AppendString(FIELD_INSTALL_COST);
		if (pCmdLine->GetAttributeBool(FIELD_MASS))
			Cols.AppendString(FIELD_MASS);
		if (pCmdLine->GetAttributeBool(FIELD_TOTAL_COUNT))
			Cols.AppendString(FIELD_TOTAL_COUNT);
		if (pCmdLine->GetAttributeBool(FIELD_REFERENCE))
			Cols.AppendString(FIELD_REFERENCE);

		if (pCmdLine->GetAttributeBool(FIELD_HP))
			Cols.AppendString(FIELD_HP);
		if (pCmdLine->GetAttributeBool(FIELD_HP_BONUS))
			Cols.AppendString(FIELD_HP_BONUS);
		if (pCmdLine->GetAttributeBool(FIELD_REGEN))
			Cols.AppendString(FIELD_REGEN);
		if (pCmdLine->GetAttributeBool(FIELD_FIRE_DELAY))
			Cols.AppendString(FIELD_FIRE_DELAY);
		if (pCmdLine->GetAttributeBool(FIELD_THRUST))
			Cols.AppendString(FIELD_THRUST);
		if (pCmdLine->GetAttributeBool(FIELD_POWER))
			Cols.AppendString(FIELD_POWER);

		if (pCmdLine->GetAttributeBool(FIELD_POWER_PER_SHOT))
			Cols.AppendString(FIELD_POWER_PER_SHOT);
		if (pCmdLine->GetAttributeBool(FIELD_AVERAGE_DAMAGE))
			Cols.AppendString(FIELD_AVERAGE_DAMAGE);
		if (pCmdLine->GetAttributeBool(FIELD_MAX_SPEED))
			Cols.AppendString(FIELD_MAX_SPEED);

		//	Output the header

		for (j = 0; j < Cols.GetCount(); j++)
			{
			if (j != 0)
				printf("\t");

			printf(Cols.GetStringValue(j).GetASCIIZPointer());
			}

		printf("\n");

		//	Output each row

		for (i = 0; i < Table.GetCount(); i++)
			{
			CItemType *pType = (CItemType *)Table.GetValue(i);

			for (j = 0; j < Cols.GetCount(); j++)
				{
				if (j != 0)
					printf("\t");

				CString sField = Cols.GetStringValue(j);
				CString sValue = pType->GetDataField(sField);

				if (strEquals(sField, FIELD_AVERAGE_DAMAGE) || strEquals(sField, FIELD_POWER_PER_SHOT))
					printf("%.2f", strToInt(sValue, 0, NULL) / 1000.0);
				else if (strEquals(sField, FIELD_POWER))
					printf("%.1f", strToInt(sValue, 0, NULL) / 1000.0);
				else if (strEquals(sField, FIELD_TOTAL_COUNT))
					{
					double rCount = 0.0;

					CString sKey = strFromInt(pType->GetUNID(), FALSE);
					EntryInfo *pEntry;
					if (TotalCount.Lookup(sKey, (CObject **)&pEntry) == NOERROR)
						rCount = pEntry->rTotalCount;

					printf("%.2f", rCount);
					}
				else
					printf(sValue.GetASCIIZPointer());
				}

			printf("\n");
			}

		printf("\n");
		}
	else
		printf("No entries match criteria.\n");
	}
예제 #9
0
void CPlayerGameStats::GenerateGameStats (CGameStats &Stats, CSpaceObject *pPlayerShip, bool bGameOver) const

//	GenerateGameStats
//
//	Generates a stats for everything we track

	{
	int j;

	CShip *pShip = (pPlayerShip ? pPlayerShip->AsShip() : NULL);
	if (pShip == NULL)
		return;

	CPlayerShipController *pPlayer = (CPlayerShipController *)pShip->GetController();
	if (pPlayer == NULL)
		return;

	CSovereign *pPlayerSovereign = g_pUniverse->FindSovereign(g_PlayerSovereignUNID);
	if (pPlayerSovereign == NULL)
		return;

	//	Base stats

	Stats.Insert(CONSTLIT("Genome"), strCapitalize(GetGenomeName(pPlayer->GetPlayerGenome())));
	Stats.Insert(CONSTLIT("Score"), strFormatInteger(CalcEndGameScore(), -1, FORMAT_THOUSAND_SEPARATOR | FORMAT_UNSIGNED));
	Stats.Insert(CONSTLIT("Ship class"), pShip->GetNounPhrase(0));

	CTimeSpan Time = GetPlayTime();
	if (!Time.IsBlank())
		Stats.Insert(CONSTLIT("Time played"), Time.Format(NULL_STR));

#ifdef REAL_TIME
	Time = GetGameTime();
	if (!Time.IsBlank())
		Stats.Insert(CONSTLIT("Time elapsed in game"), Time.Format(NULL_STR));
#endif

	//	Some combat stats

	CString sDestroyed = GetStat(ENEMY_SHIPS_DESTROYED_STAT);
	if (!sDestroyed.IsBlank())
		Stats.Insert(CONSTLIT("Enemy ships destroyed"), sDestroyed, CONSTLIT("combat"));

	sDestroyed = GetStat(FRIENDLY_SHIPS_DESTROYED_STAT);
	if (!sDestroyed.IsBlank())
		Stats.Insert(CONSTLIT("Friendly ships destroyed"), sDestroyed, CONSTLIT("combat"));

	sDestroyed = GetStat(ENEMY_STATIONS_DESTROYED_STAT);
	if (!sDestroyed.IsBlank())
		Stats.Insert(CONSTLIT("Enemy stations destroyed"), sDestroyed, CONSTLIT("combat"));

	sDestroyed = GetStat(FRIENDLY_STATIONS_DESTROYED_STAT);
	if (!sDestroyed.IsBlank())
		Stats.Insert(CONSTLIT("Friendly stations destroyed"), sDestroyed, CONSTLIT("combat"));

	//	Add stat for every station destroyed

	CStatCounterArray CounterArray;

	CMapIterator i;
	m_StationStats.Reset(i);
	while (m_StationStats.HasMore(i))
		{
		SStationTypeStats *pStats;
		DWORD dwUNID = m_StationStats.GetNext(i, &pStats);
		CStationType *pType = g_pUniverse->FindStationType(dwUNID);
		if (pType == NULL)
			continue;

		CString sName = pType->GetNounPhrase(0);
		CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - pType->GetLevel(), sName);

		if (pType->GetSovereign()->IsEnemy(pPlayerSovereign))
			CounterArray.Insert(sName, pStats->iDestroyed, CONSTLIT("Enemy stations destroyed"), sSort);
		else
			CounterArray.Insert(sName, pStats->iDestroyed, CONSTLIT("Friendly stations destroyed"), sSort);
		}

	CounterArray.GenerateGameStats(Stats);
		
	//	Add stat for every ship class destroyed

	CounterArray.DeleteAll();
	m_ShipStats.Reset(i);
	while (m_ShipStats.HasMore(i))
		{
		SShipClassStats *pStats;
		DWORD dwUNID = m_ShipStats.GetNext(i, &pStats);
		CShipClass *pClass = g_pUniverse->FindShipClass(dwUNID);
		if (pClass == NULL)
			continue;

		CString sName = pClass->GetNounPhrase(0);
		CString sSort = strPatternSubst(CONSTLIT("%09d%s"), 100000000 - pClass->GetScore(), sName);

		if (pStats->iEnemyDestroyed > 0)
			CounterArray.Insert(sName, pStats->iEnemyDestroyed, CONSTLIT("Enemy ships destroyed"), sSort);

		if (pStats->iFriendDestroyed > 0)
			CounterArray.Insert(sName, pStats->iFriendDestroyed, CONSTLIT("Friendly ships destroyed"), sSort);
		}

	CounterArray.GenerateGameStats(Stats);

	//	Add stat for every weapon fired

	m_ItemStats.Reset(i);
	while (m_ItemStats.HasMore(i))
		{
		SItemTypeStats *pStats;
		DWORD dwUNID = m_ItemStats.GetNext(i, &pStats);
		CItemType *pItemType = g_pUniverse->FindItemType(dwUNID);
		if (pItemType == NULL)
			continue;

		CString sName = pItemType->GetNounPhrase(nounShort);
		CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - pItemType->GetLevel(), sName);

		//	Installed items

		if (pStats->dwFirstInstalled != INVALID_TIME)
			Stats.Insert(sName, NULL_STR, CONSTLIT("Items installed"), sSort);

		if (pStats->iCountFired > 0)
			Stats.Insert(sName, 
					strFormatInteger(pStats->iCountFired, -1, FORMAT_THOUSAND_SEPARATOR | FORMAT_UNSIGNED), 
					CONSTLIT("Weapons fired"), 
					sSort);
		}

	//	Stats for player equipment (but only if the game is done)

	if (bGameOver)
		{
		TSortMap<CString, CItem> InstalledItems;

		//	First we generate a sorted list of installed items
		//	(We do this in case there are multiple of the same device/armor so that
		//	we can coalesce them together into a single line).

		CItemListManipulator ItemList(pShip->GetItemList());
		ItemList.ResetCursor();
		while (ItemList.MoveCursorForward())
			{
			const CItem &Item(ItemList.GetItemAtCursor());

			if (Item.IsInstalled())
				{
				CString sEnhancement = Item.GetEnhancedDesc(pShip);
				CString sItemName = Item.GetNounPhrase(nounActual | nounCountOnly | nounShort);
				CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement));

				bool bInserted;
				CItem *pEntry = InstalledItems.SetAt(sLine, &bInserted);
				if (bInserted)
					{
					*pEntry = Item;
					pEntry->SetCount(1);
					}
				else
					pEntry->SetCount(pEntry->GetCount() + 1);
				}
			}

		//	Now add all the installed items to the stats

		for (j = 0; j < InstalledItems.GetCount(); j++)
			{
			//	Redo the line now that we know the proper count

			CString sEnhancement = InstalledItems[j].GetEnhancedDesc(pShip);
			CString sItemName = InstalledItems[j].GetNounPhrase(nounActual | nounCountOnly);
			CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement));

			//	Compute the sort order

			int iOrder;
			switch (InstalledItems[j].GetType()->GetCategory())
				{
				case itemcatWeapon:
					iOrder = 0;
					break;

				case itemcatLauncher:
					iOrder = 1;
					break;

				case itemcatShields:
					iOrder = 2;
					break;

				case itemcatArmor:
					iOrder = 3;
					break;

				case itemcatReactor:
					iOrder = 4;
					break;

				case itemcatDrive:
					iOrder = 5;
					break;

				default:
					iOrder = 6;
					break;
				}

			CString sSort = strPatternSubst(CONSTLIT("%d%03d%s"), iOrder, 100 - InstalledItems[j].GetType()->GetLevel(), sLine);
			Stats.Insert(sLine, NULL_STR, CONSTLIT("Final equipment"), sSort);
			}

		//	Add the remaining items

		ItemList.ResetCursor();
		while (ItemList.MoveCursorForward())
			{
			const CItem &Item(ItemList.GetItemAtCursor());

			if (!Item.IsInstalled())
				{
				CString sEnhancement = Item.GetEnhancedDesc(pShip);
				CString sItemName = Item.GetNounPhrase(nounActual | nounCountOnly);
				CString sLine = (sEnhancement.IsBlank() ? sItemName : strPatternSubst(CONSTLIT("%s [%s]"), sItemName, sEnhancement));
				CString sSort = strPatternSubst(CONSTLIT("%03d%s"), 100 - Item.GetType()->GetLevel(), sLine);

				Stats.Insert(sLine, NULL_STR, CONSTLIT("Final items"), sSort);
				}
			}
		}
	}