Exemplo n.º 1
0
int CShieldClass::GetDamageEffectiveness (CSpaceObject *pAttacker, CInstalledDevice *pWeapon)

//	GetDamageEffectiveness
//
//	Returns the effectiveness of the given weapon against this shield.
//
//	< 0		The weapon is ineffective against us.
//	0-99	The weapon is less effective than average.
//	100		The weapon has average effectiveness
//	> 100	The weapon is more effective than average.

	{
	const DamageDesc *pDamage = pWeapon->GetDamageDesc(CItemCtx(pAttacker, pWeapon));
	if (pDamage == NULL)
		return 100;

	int iBonus = m_DamageAdj.GetHPBonus(pDamage->GetDamageType());
	if (iBonus <= -100)
		return -1;

	//	Compute score based on bonus

	int iScore;
	if (iBonus <= 0)
		iScore = 100 - iBonus;
	else
		iScore = 100 - Min(100, (iBonus / 2));

	//	See if the weapon does extra damage to shields

	if (pDamage->GetShieldDamageLevel())
		{
		int iAdj = 100 * Max(100, 300 + (50 * (pDamage->GetShieldDamageLevel() - GetLevel()))) / 100;
		iScore += (iAdj / 2);
		}

	//	Done

	return iScore;
	}
Exemplo n.º 2
0
int CShieldClass::CalcBalance (void)

//	CalcBalance
//
//	Computes the relative balance of this shield relative to it level

	{
	int i;
	int iBalance = 0;

	SStdStats *pStd = GetStdStats(GetLevel());
	if (pStd == NULL)
		return 0;

	//	Calc HPs. +1 for each 1% above standard HP
	//	If hp is below the standard, then invert the ratio
	//	(i.e., 50% below is 1/0.5 or half strength, which
	//	counts as -100).

	int iMaxHP;
	CalcMinMaxHP(CItemCtx(), m_iMaxCharges, 0, 0, NULL, &iMaxHP);

	int iDiff = (iMaxHP - pStd->iHP);
	if (iDiff > 0)
		iBalance += iDiff * 100 / pStd->iHP;
	else if (iMaxHP > 0)
		iBalance -= (pStd->iHP * 100 / iMaxHP) - 100;
	else
		iBalance -= 200;

	//	Compute the regen HP for each 180 ticks
	//	+1 for each 1% above standard rate

	int iRegen = (int)m_Regen.GetHPPer180();
	iDiff = (iRegen - pStd->iRegen);
	if (iDiff > 0)
		iBalance += iDiff * 100 / pStd->iHP;
	else if (iRegen > 0)
		iBalance -= (pStd->iRegen * 100 / iRegen) - 100;
	else
		iBalance -= 200;

	//	Account for damage adjustments

	int iBalanceAdj = 0;
	for (i = 0; i < damageCount; i++)
		{
		int iStdAdj;
		int iDamageAdj;
		m_DamageAdj.GetAdjAndDefault((DamageTypes)i, &iDamageAdj, &iStdAdj);

		if (iStdAdj != iDamageAdj)
			{
			if (iDamageAdj > 0)
				{
				int iBonus = (int)((100.0 * (iStdAdj - iDamageAdj) / iDamageAdj) + 0.5);

				if (iBonus > 0)
					iBalanceAdj += iBonus / 4;
				else
					iBalanceAdj -= ((int)((100.0 * iDamageAdj / iStdAdj) + 0.5) - 100) / 4;
				}
			else if (iStdAdj > 0)
				{
				iBalanceAdj += iStdAdj;
				}
			}
		}

	iBalance += Max(Min(iBalanceAdj, 100), -100);

	//	Done

	return iBalance;
	}
Exemplo n.º 3
0
bool CShieldClass::AbsorbDamage (CInstalledDevice *pDevice, CSpaceObject *pShip, SDamageCtx &Ctx)

//	AbsorbDamage
//
//	Absorbs damage.
//	NOTE: We always set Ctx.iAbsorb properly, regardless of the return value.

	{
	DEBUG_TRY

	//	If we're depleted then we cannot absorb anything

	Ctx.iHPLeft = GetHPLeft(pDevice, pShip);
	if (Ctx.iHPLeft == 0)
		{
		Ctx.iAbsorb = 0;
		return false;
		}

	//	Calculate how much we will absorb

	int iAbsorbAdj = (Ctx.Damage.GetDamageType() == damageGeneric ? 100 : m_iAbsorbAdj[Ctx.Damage.GetDamageType()]);
	Ctx.iAbsorb = (Ctx.iDamage * iAbsorbAdj) / 100;
	if (pDevice->GetMods().IsNotEmpty())
		Ctx.iAbsorb = Ctx.iAbsorb * pDevice->GetMods().GetAbsorbAdj(Ctx.Damage) / 100;

	//	Compute how much damage we take (based on the type of damage)

	int iAdj = GetDamageAdj(pDevice->GetMods(), Ctx.Damage);
	Ctx.iShieldDamage = (Ctx.iAbsorb * iAdj) / 100;

	//	If shield generator is damaged then sometimes we take extra damage

	if (pDevice->IsDamaged() || pDevice->IsDisrupted())
		{
		int iRoll = mathRandom(1, 100);

		if (iRoll <= 10)
			Ctx.iAbsorb = 75 * Ctx.iAbsorb / 100;
		else if (iRoll <= 25)
			Ctx.iShieldDamage *= 2;
		}

	//	If the amount of shield damage is greater than HP left, then scale
	//	the amount of HP that we aborb

	if (Ctx.iShieldDamage > Ctx.iHPLeft)
		{
		//	ASSERT: We know that iShieldDamage is > 0 because iHPLeft is > 0.

		Ctx.iAbsorb = Ctx.iHPLeft * Ctx.iAbsorb / Ctx.iShieldDamage;
		Ctx.iShieldDamage = Ctx.iHPLeft;
		}

	//	See if we're reflective

	int iReflectChance;
	if (!pDevice->GetMods().IsReflective(Ctx.Damage, &iReflectChance))
		iReflectChance = 0;
	if (m_Reflective.InSet(Ctx.Damage.GetDamageType()))
		iReflectChance = Max(iReflectChance, MAX_REFLECTION_CHANCE);
	if (iReflectChance 
			&& Ctx.pCause 
			&& Ctx.Damage.GetShieldDamageLevel() == 0)
		{
		//	Compute the chance that we will reflect (based on the strength of
		//	our shields)

		int iMaxHP = GetMaxHP(pDevice, pShip);
		int iEfficiency = (iMaxHP == 0 ? 100 : 50 + (Ctx.iHPLeft * 50 / iMaxHP));
		int iChance = iEfficiency * iReflectChance / 100;

		//	See if we reflect

		if (Ctx.bReflect = (mathRandom(1, 100) <= iChance))
			{
			Ctx.iOriginalAbsorb = Ctx.iAbsorb;
			Ctx.iOriginalShieldDamage = Ctx.iShieldDamage;
			Ctx.iAbsorb = Ctx.iDamage;
			Ctx.iShieldDamage = 0;
			}
		}
	else
		Ctx.bReflect = false;

	//	Give custom damage a chance to react. These events can modify the
	//	following variables:
	//
	//	Ctx.bReflect
	//	Ctx.iAbsorb
	//	Ctx.iShieldDamage
	//
	//	OR
	//
	//	Ctx.iDamage (if we skip further processing)

	if (Ctx.pDesc->FireOnDamageShields(Ctx, pDevice->GetDeviceSlot()))
		return (Ctx.iDamage == 0);

	FireOnShieldDamage(CItemCtx(pShip, pDevice), Ctx);

	//	If we reflect, then create the reflection

	if (Ctx.bReflect)
		Ctx.pCause->CreateReflection(Ctx.vHitPos, (Ctx.iDirection + 120 + mathRandom(0, 120)) % 360);

	//	Create shield effect

	if (Ctx.iAbsorb || Ctx.bReflect)
		{
		if (m_pHitEffect)
			m_pHitEffect->CreateEffect(pShip->GetSystem(),
					NULL,
					Ctx.vHitPos,
					pShip->GetVel(),
					Ctx.iDirection);
		}

	//	Shield takes damage

	if (Ctx.iShieldDamage > 0)
		{
		if (Ctx.iShieldDamage >= Ctx.iHPLeft)
			SetDepleted(pDevice, pShip);
		else
			SetHPLeft(pDevice, Ctx.iHPLeft - Ctx.iShieldDamage);

		pShip->OnComponentChanged(comShields);
		}

	//	Set the remaining damage

	Ctx.iDamage -= Ctx.iAbsorb;
	return (Ctx.iDamage == 0);

	DEBUG_CATCH
	}
Exemplo n.º 4
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");
		}
	}
Exemplo n.º 5
0
CurrencyValue CSingleItem::GetAverageValue (int iLevel)

//	GetAverageValue
//
//	Returns the average value (in credits)

	{
	return CEconomyType::ExchangeToCredits(m_pItemType->GetCurrencyType(), m_pItemType->GetValue(CItemCtx(), true));
	}
Exemplo n.º 6
0
CurrencyValue CRandomItems::GetAverageValue (int iLevel)

//	GetAverageValue
//
//	Returns the average value.

	{
	int i;

	//	If this is a dynamic table we need to compute all levels

	if (m_bDynamicLevelFrequency)
		{
		Metric rTotal = 0.0;
		InitTable(GenerateLevelFrequency(m_sLevelFrequency, iLevel));
		m_iDynamicLevel = iLevel;

		for (i = 0; i < m_iCount; i++)
			{
			CItemType *pType = m_Table[i].pType;
			CurrencyValue ItemValue = CEconomyType::ExchangeToCredits(pType->GetCurrencyType(), pType->GetValue(CItemCtx(), true));
			rTotal += (pType->GetNumberAppearing().GetAveValueFloat() * (Metric)ItemValue * (Metric)m_Table[i].iProbability / 1000.0);
			}

		return (CurrencyValue)(rTotal + 0.5);
		}

	//	Otherwise the table is already initialized.

	else
		{
		//	Average value is proportional to chances.

		Metric rTotal = 0.0;
		for (i = 0; i < m_iCount; i++)
			{
			CItemType *pType = m_Table[i].pType;
			CurrencyValue ItemValue = CEconomyType::ExchangeToCredits(pType->GetCurrencyType(), pType->GetValue(CItemCtx(), true));
			rTotal += (pType->GetNumberAppearing().GetAveValueFloat() * (Metric)ItemValue * (Metric)m_Table[i].iProbability / 1000.0);
			}

		return (CurrencyValue)(rTotal + 0.5);
		}
	}
Exemplo n.º 7
0
void CNewGameSession::SetShipClass (CShipClass *pClass, int x, int y, int cxWidth)

//	SetShipClass
//
//	Sets the ship class

	{
	int i;

	g_pUniverse->SetLogImageLoad(false);

	const CPlayerSettings *pPlayerSettings = pClass->GetPlayerSettings();

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

	//	Ship class name

	SetShipClassName(pClass->GetNounPhrase(nounGeneric), x, y, cxWidth);
	SetShipClassDesc(pPlayerSettings->GetDesc(), x, y, cxWidth);

	//	Offset

	int yOffset = SMALL_BUTTON_HEIGHT + SMALL_SPACING_VERT + MediumBoldFont.GetHeight() + 2 * SubTitleFont.GetHeight();

	//	Ship class image

	SetShipClassImage(pClass, x, y + yOffset, cxWidth);

	//	Delete previous info

	DeleteElement(ID_SHIP_CLASS_INFO);

	//	Create a sequencer for all class info components

	CAniSequencer *pClassInfo;
	CAniSequencer::Create(CVector(x, y + yOffset + SubTitleFont.GetHeight()), &pClassInfo);
	pClassInfo->SetID(ID_SHIP_CLASS_INFO);

	//	Generate default devices for the ship class

	CDeviceDescList Devices;
	pClass->GenerateDevices(1, Devices);

	//	Generate list of all weapons, sorted by level and name

	TSortMap<CString, CItem> RightSide;
	for (i = 0; i < Devices.GetCount(); i++)
		{
        const CItem &DevItem = Devices.GetDeviceDesc(i).Item;
		CDeviceClass *pDevice = Devices.GetDeviceClass(i);
		if (pDevice->GetCategory() == itemcatWeapon ||
				pDevice->GetCategory() == itemcatLauncher)
			RightSide.Insert(strPatternSubst(CONSTLIT("%02d_%02d_%s"), 1, DevItem.GetLevel(), DevItem.GetNounPhrase(CItemCtx())), DevItem);
		}

	//	Add shields

	TSortMap<CString, CItem> LeftSide;
    const SDeviceDesc *pShields = Devices.GetDeviceDescByName(devShields);
	if (pShields)
		RightSide.Insert(strPatternSubst(CONSTLIT("%02d_%02d_%s"), 2, pShields->Item.GetLevel(), pShields->Item.GetNounPhrase(CItemCtx())), pShields->Item);

	//	Add armor

	RightSide.Insert(CONSTLIT("03"), CItem(g_pUniverse->GetItemType(0), SPECIAL_ARMOR));

	//	Add reactor

	LeftSide.Insert(CONSTLIT("01"), CItem(g_pUniverse->GetItemType(0), SPECIAL_REACTOR));

	//	Add engines

	LeftSide.Insert(CONSTLIT("02"), CItem(g_pUniverse->GetItemType(0), SPECIAL_DRIVE));

	//	Add cargo

	LeftSide.Insert(CONSTLIT("03"), CItem(g_pUniverse->GetItemType(0), SPECIAL_CARGO));

	//	Add misc devices

	for (i = 0; i < Devices.GetCount(); i++)
		{
        const CItem &DevItem = Devices.GetDeviceDesc(i).Item;
		CDeviceClass *pDevice = Devices.GetDeviceClass(i);
		if (pDevice->GetCategory() == itemcatMiscDevice)
			LeftSide.Insert(strPatternSubst(CONSTLIT("%02d_%02d_%s"), 4, DevItem.GetLevel(), DevItem.GetNounPhrase(CItemCtx())), DevItem);
		}

	//	Add device slots

	LeftSide.Insert(CONSTLIT("05"), CItem(g_pUniverse->GetItemType(0), SPECIAL_DEVICE_SLOTS));

	//	Set the ship class info. All weapons go to the right of the ship image

	int xPos = (cxWidth / 2) + (SHIP_IMAGE_RECT_WIDTH / 2);
	int yPos = 0;
	int cxInfo = (cxWidth - xPos);

	for (i = 0; i < RightSide.GetCount(); i++)
		{
		int cyInfo;
		IAnimatron *pInfo;
		AddClassInfo(pClass, Devices, RightSide[i], xPos, yPos, cxInfo, 0, &cyInfo, &pInfo);

		pClassInfo->AddTrack(pInfo, 0);
		yPos += cyInfo + ITEM_INFO_PADDING_VERT;
		}

	//	Misc devices go on the left

	xPos = (cxWidth / 2) - (SHIP_IMAGE_RECT_WIDTH / 2);
	yPos = 0;
	cxInfo = xPos;

	for (i = 0; i < LeftSide.GetCount(); i++)
		{
		int cyInfo;
		IAnimatron *pInfo;
		AddClassInfo(pClass, Devices, LeftSide[i], xPos, yPos, cxInfo, CUIHelper::OPTION_ITEM_RIGHT_ALIGN, &cyInfo, &pInfo);

		pClassInfo->AddTrack(pInfo, 0);
		yPos += cyInfo + ITEM_INFO_PADDING_VERT;
		}

	m_pRoot->AddLine(pClassInfo);

	g_pUniverse->SetLogImageLoad(true);
	}