Example #1
0
int CArmorClass::GetMaxHP (CItemCtx &ItemCtx)

//	GetMaxHP
//
//	Returns the max HP for this kind of armor

	{
	//	Start with hit points defined by the class

	int iHP = m_iHitPoints;

	//	Fire event to compute HP, if necessary

	iHP = FireGetMaxHP(ItemCtx, iHP);

	//	Add mods

	const CItemEnhancement &Mods = ItemCtx.GetMods();
	if (Mods.IsNotEmpty())
		iHP = iHP * Mods.GetHPAdj() / 100;

	//	Add complete bonus

	CInstalledArmor *pSect = ItemCtx.GetArmor();
	if (pSect && pSect->IsComplete())
		iHP += m_iArmorCompleteBonus;

	//	Done

	return iHP;
	}
Example #2
0
int CArmorClass::FireGetMaxHP (CItemCtx &ItemCtx, int iMaxHP) const

//	FireGetMaxHP
//
//	Fire GetMaxHP event

	{
	SEventHandlerDesc Event;
	if (FindEventHandlerArmorClass(evtGetMaxHP, &Event))
		{
		//	Setup arguments

		CCodeChainCtx Ctx;
		Ctx.SaveAndDefineSourceVar(ItemCtx.GetSource());
		Ctx.SaveAndDefineItemVar(ItemCtx);

		Ctx.DefineInteger(CONSTLIT("aMaxHP"), iMaxHP);

		ICCItem *pResult = Ctx.Run(Event);

		if (pResult->IsError())
			ItemCtx.GetSource()->ReportEventError(GET_MAX_HP_EVENT, pResult);
		else if (!pResult->IsNil())
			iMaxHP = Max(0, pResult->GetIntegerValue());

		Ctx.Discard(pResult);
		}

	return iMaxHP;
	}
Example #3
0
bool CDeviceClass::AccumulateEnhancements (CItemCtx &Device, CInstalledDevice *pTarget, TArray<CString> &EnhancementIDs, CItemEnhancementStack *pEnhancements)

//	AccumulateEnhancements
//
//	If this device can enhance pTarget, then we add to the list of enhancements.

	{
	int i;
	bool bEnhanced = false;

	CInstalledDevice *pDevice = Device.GetDevice();
	CSpaceObject *pSource = Device.GetSource();

	//	See if we can enhance the target device

	if (pDevice == NULL 
			|| (pDevice->IsEnabled() && !pDevice->IsDamaged()))
		{
		for (i = 0; i < m_Enhancements.GetCount(); i++)
			{
			//	If this type of enhancement has already been applied, skip it

			if (!m_Enhancements[i].sType.IsBlank()
					&& EnhancementIDs.Find(m_Enhancements[i].sType))
				continue;

			//	If we don't match the criteria, skip it.

			if (pSource 
					&& pTarget
					&& !pSource->GetItemForDevice(pTarget).MatchesCriteria(m_Enhancements[i].Criteria))
				continue;

			//	Add the enhancement

			pEnhancements->Insert(m_Enhancements[i].Enhancement);
			bEnhanced = true;

			//	Remember that we added this enhancement class

			if (!m_Enhancements[i].sType.IsBlank())
				EnhancementIDs.Insert(m_Enhancements[i].sType);
			}
		}

	//	Let sub-classes add their own

	if (OnAccumulateEnhancements(Device, pTarget, EnhancementIDs, pEnhancements))
		bEnhanced = true;

	//	Done

	return bEnhanced;
	}
Example #4
0
void CDeviceClass::AccumulateAttributes (CItemCtx &ItemCtx, int iVariant, TArray<SDisplayAttribute> *retList)

//	AccumulateAttributes
//
//	Add display attributes to the list.

	{
	//	Add general device attributes. If we have a variant, then it means 
	//	we're interested in the attributes for a missile/ammo of the device 
	//	(not the device itself).

	if (iVariant == -1)
		{
		CInstalledDevice *pDevice = ItemCtx.GetDevice();

		//	Linked-fire

		DWORD dwOptions = GetLinkedFireOptions(ItemCtx);
		if (dwOptions != 0)
			retList->Insert(SDisplayAttribute(attribPositive, CONSTLIT("linked-fire")));
		}

	//	Let our subclasses add their own attributes

	OnAccumulateAttributes(ItemCtx, iVariant, retList);
	}
Example #5
0
void CArmorClass::CalcAdjustedDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	CalcAdjustedDamage
//
//	Modifies Ctx.iDamage to account for damage type adjustments, etc.

	{
	CInstalledArmor *pArmor = ItemCtx.GetArmor();

	//	Adjust for special armor damage:
	//
	//	<0	=	2.5x damage
	//	0	=	2x damage
	//	1	=	1.5x damage
	//	2	=	1.25x damage
	//	>2	=	1x damage

	int iDamageLevel = Ctx.Damage.GetArmorDamageLevel();
	if (iDamageLevel > 0)
		Ctx.iDamage = (CalcArmorDamageAdj(Ctx.Damage) * Ctx.iDamage + 50) / 100;

	//	Adjust for damage type

	int iDamageAdj = GetDamageAdj((pArmor ? pArmor->GetMods() : CItemEnhancement()), Ctx.Damage);
	Ctx.iDamage = (iDamageAdj * Ctx.iDamage + 50) / 100;
	}
Example #6
0
void CShieldClass::CalcMinMaxHP (CItemCtx &Ctx, int iCharges, int iArmorSegs, int iTotalHP, int *retiMin, int *retiMax) const

//	CalcMinMaxHP
//
//	Returns the min and max HP of this shield
//
//	iCharges = m_iMaxCharges or the current charges on item
//	iArmorSegs = count of armor segments on ship (or 0)
//	iTotalHP = current total HP of all armor segments (or 0)

	{
	int iMax = m_iHitPoints;
	int iMin = iMax;

	if (m_iExtraHPPerCharge)
		iMax = Max(0, iMax + (m_iExtraHPPerCharge * iCharges));

	if (m_iArmorShield)
		{
		iMin = m_iArmorShield;

		if (iArmorSegs > 0)
			iMax = Min(iMax, ((m_iArmorShield * iTotalHP / iArmorSegs) + 5) / 10);
		}

	//	If we're installed, fire the custom event to get max HPs

	if (Ctx.GetSource() && Ctx.GetDevice())
		iMax = FireGetMaxHP(Ctx.GetDevice(), Ctx.GetSource(), iMax);

	//	Mods

	const CItemEnhancement &Mods = Ctx.GetMods();
	if (Mods.IsNotEmpty())
		iMax = iMax * Mods.GetHPAdj() / 100;

	//	Done

	if (iMin > iMax)
		iMin = iMax;

	if (retiMin)
		*retiMin = iMin;

	if (retiMax)
		*retiMax = iMax;
	}
void CCodeChainCtx::DefineItem (const CString &sVar, CItemCtx &ItemCtx)

//	DefineItem
//
//	Defines a CItem variable

	{
	ICCItem *pItem = ItemCtx.CreateItemVariable(m_CC);
	m_CC.DefineGlobal(sVar, pItem);
	pItem->Discard(&m_CC);
	}
Example #8
0
CString CShieldClass::GetReference (CItemCtx &Ctx, int iVariant, DWORD dwFlags)

//	GetReference
//
//	Returns a string that describes the basic attributes
//	of this shield
//
//	Example:
//
//		20 hp (average regen); 100MW

	{
	int i;

	CString sReference;
	CString sRegeneration;
	const CItemEnhancement &Mods = Ctx.GetMods();

	//	Compute the strength string

	int iMin, iMax;
	CalcMinMaxHP(Ctx, m_iMaxCharges, 0, 0, &iMin, &iMax);

	//	Compute the regeneration

	if (m_iRegenHP > 0)
		{
		int iRate = (int)((10.0 * g_TicksPerSecond * m_iRegenHP / m_iRegenRate) + 0.5);
		if (iRate == 0)
			sRegeneration = CONSTLIT("<0.1 hp/sec");
		else if ((iRate % 10) == 0)
			sRegeneration = strPatternSubst(CONSTLIT("%d hp/sec"), iRate / 10);
		else
			sRegeneration = strPatternSubst(CONSTLIT("%d.%d hp/sec"), iRate / 10, iRate % 10);
		}
	else
		sRegeneration = CONSTLIT("none");

	sReference = strPatternSubst("%s — regen @ %s", 
			GetReferencePower(Ctx),
			sRegeneration);

	//	Reflection

	for (i = 0; i < damageCount; i++)
		{
		if (m_Reflective.InSet((DamageTypes)i)
				|| (Mods.IsReflective() && Mods.GetDamageType() == i))
			sReference.Append(strPatternSubst(CONSTLIT(" — %s-reflecting"), GetDamageShortName((DamageTypes)i)));
		}

	return sReference;
	}
Example #9
0
bool CArmorClass::IsReflective (CItemCtx &ItemCtx, const DamageDesc &Damage)

//	IsReflective
//
//	Returns TRUE if the armor reflects this damage

	{
	const CItemEnhancement &Mods = ItemCtx.GetMods();

	int iReflectChance = 0;

	//	Base armor chance

	if (m_Reflective.InSet(Damage.GetDamageType()))
		iReflectChance = MAX_REFLECTION_CHANCE;

	//	Mods

	int iModReflect;
	if (Mods.IsNotEmpty() && Mods.IsReflective(Damage, &iModReflect))
		iReflectChance = Max(iReflectChance, iModReflect);

	//	Done

	if (iReflectChance)
		{
		CInstalledArmor *pSect = ItemCtx.GetArmor();

		int iMaxHP = GetMaxHP(ItemCtx);
		int iHP = (pSect ? pSect->GetHitPoints() : iMaxHP);

		//	Adjust based on how damaged the armor is

		iReflectChance = (iMaxHP > 0 ? iHP * iReflectChance / iMaxHP : iReflectChance);

		return (mathRandom(1, 100) <= iReflectChance);
		}
	else
		return false;
	}
Example #10
0
void CArmorClass::CalcAdjustedDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	CalcAdjustedDamage
//
//	Modifies Ctx.iDamage to account for damage type adjustments, etc.

	{
	CInstalledArmor *pArmor = ItemCtx.GetArmor();

	//	Adjust for special armor damage:
	//
	//	<0	=	2.5x damage
	//	0	=	2x damage
	//	1	=	1.5x damage
	//	2	=	1.25x damage
	//	>2	=	1x damage

	int iDamageLevel = Ctx.Damage.GetArmorDamageLevel();
	if (iDamageLevel > 0)
		{
		int iDiff = m_pItemType->GetLevel() - iDamageLevel;
		int iAdj;

		switch (iDiff)
			{
			case 0:
				iAdj = 200;
				break;

			case 1:
				iAdj = 150;
				break;

			case 2:
				iAdj = 125;
				break;

			default:
				if (iDiff < 0)
					iAdj = 250;
				else
					iAdj = 100;
			}

		Ctx.iDamage = (iAdj * Ctx.iDamage + 50) / 100;
		}

	//	Adjust for damage type

	int iDamageAdj = GetDamageAdj((pArmor ? pArmor->GetMods() : CItemEnhancement()), Ctx.Damage);
	Ctx.iDamage = (iDamageAdj * Ctx.iDamage + 50) / 100;
	}
int CItemEnhancementStack::CalcActivateDelay (CItemCtx &DeviceCtx) const

//	CalcActivateDelay
//
//	Calculates the activation delay (in ticks) for the given device if we apply
//	this enhancement stack.

	{
	int i;

	CInstalledDevice *pDevice = DeviceCtx.GetDevice();
	if (pDevice == NULL)
		return 0;

	Metric rDelay = -1.0;
	for (i = 0; i < m_Stack.GetCount(); i++)
		{
		int iMin, iMax;
		int iAdj = m_Stack[i].GetActivateRateAdj(&iMin, &iMax);
		if (iAdj != 100)
			{
			if (rDelay < 0.0)
				{
				pDevice->SetActivateDelayAdj(100);
				rDelay = pDevice->GetActivateDelay(DeviceCtx.GetSource());
				}

			rDelay = iAdj * rDelay / 100.0;
			if (rDelay < (Metric)iMin)
				rDelay = (Metric)iMin;
			else if (iMax > 0 && rDelay > (Metric)iMax)
				rDelay = (Metric)iMax;
			}
		}

	return (rDelay < 0.0 ? 100 : (int)(rDelay + 0.5));
	}
Example #12
0
int CItemEnhancementStack::CalcActivateDelay (CItemCtx &DeviceCtx) const

//	CalcActivateDelay
//
//	Calculates the activation delay (in ticks) for the given device if we apply
//	this enhancement stack.

	{
	int i;

	CInstalledDevice *pDevice = DeviceCtx.GetDevice();
	if (pDevice == NULL)
		return 0;

	//	Get the raw activation delay. NOTE: This DOES NOT include
	//	any enhancements on the item.

	Metric rDelay = pDevice->GetClass()->GetActivateDelay(pDevice, DeviceCtx.GetSource());

	//	Apply enhancements (including on the item itself)

	for (i = 0; i < m_Stack.GetCount(); i++)
		{
		int iMin, iMax;
		int iAdj = m_Stack[i].GetActivateRateAdj(&iMin, &iMax);
		if (iAdj != 100)
			{
			rDelay = iAdj * rDelay / 100.0;
			if (rDelay < (Metric)iMin)
				rDelay = (Metric)iMin;
			else if (iMax > 0 && rDelay > (Metric)iMax)
				rDelay = (Metric)iMax;
			}
		}

	return (int)(rDelay + 0.5);
	}
Example #13
0
void CArmorClass::FireOnArmorDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	FireOnArmorDamage
//
//	Fires OnArmorDamage event

	{
	SEventHandlerDesc Event;
	if (FindEventHandlerArmorClass(evtOnArmorDamage, &Event))
		{
		//	Setup arguments

		CCodeChainCtx CCCtx;
		CCCtx.SaveAndDefineSourceVar(ItemCtx.GetSource());
		CCCtx.SaveAndDefineItemVar(ItemCtx);

		CCCtx.DefineInteger(CONSTLIT("aArmorHP"), Ctx.iHPLeft);
		CCCtx.DefineInteger(CONSTLIT("aArmorSeg"), Ctx.iSectHit);
		CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), Ctx.Attacker.GetObj());
		CCCtx.DefineSpaceObject(CONSTLIT("aCause"), Ctx.pCause);
		CCCtx.DefineDamageEffects(CONSTLIT("aDamageEffects"), Ctx);
		CCCtx.DefineInteger(CONSTLIT("aDamageHP"), Ctx.iDamage);
		CCCtx.DefineString(CONSTLIT("aDamageType"), GetDamageShortName(Ctx.Damage.GetDamageType()));
		CCCtx.DefineInteger(CONSTLIT("aHitDir"), Ctx.iDirection);
		CCCtx.DefineVector(CONSTLIT("aHitPos"), Ctx.vHitPos);
		CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (Ctx.Attacker.GetObj() ? Ctx.Attacker.GetObj()->GetOrderGiver(Ctx.Attacker.GetCause()) : NULL));
		CCCtx.DefineItemType(CONSTLIT("aWeaponType"), Ctx.pDesc->GetWeaponType());

		ICCItem *pResult = CCCtx.Run(Event);

		//	If we return Nil, then nothing

		if (pResult->IsNil())
			NULL;

		//	If we return an integer, then this is the damage that armor should take

		else if (pResult->IsInteger())
			Ctx.iDamage = pResult->GetIntegerValue();

		//	If we return a list, then we it to be a DamageEffects list (modifications to
		//	aDamageEffects)

		else if (pResult->IsList())
			LoadDamageEffectsFromItem(pResult, Ctx);

		CCCtx.Discard(pResult);
		}
	}
Example #14
0
int CShieldClass::GetPowerRating (CItemCtx &Ctx)

//	GetPowerRating
//
//	Returns the power rating of the item

	{
	int iPower = m_iPowerUse;

	const CItemEnhancement &Mods = Ctx.GetMods();
	if (Mods.IsNotEmpty())
		iPower = iPower * Mods.GetPowerAdj() / 100;

	return iPower;
	}
Example #15
0
CString CShieldClass::GetReference (CItemCtx &Ctx, int iVariant, DWORD dwFlags)

//	GetReference
//
//	Returns a string that describes the basic attributes
//	of this shield
//
//	Example:
//
//		20 hp (average regen); 100MW

	{
	int i;

	CString sReference;
	const CItemEnhancement &Mods = Ctx.GetMods();

	//	Compute the strength string

	int iMin, iMax;
	CalcMinMaxHP(Ctx, m_iMaxCharges, 0, 0, &iMin, &iMax);

	//	Compute the regeneration

	sReference = strPatternSubst("%s — regen @ %s", 
			GetReferencePower(Ctx),
			m_Regen.GetReferenceRate(CONSTLIT("hp/sec")));

	//	Reflection

	for (i = 0; i < damageCount; i++)
		{
		if (m_Reflective.InSet((DamageTypes)i)
				|| (Mods.IsReflective() && Mods.GetDamageType() == i))
			sReference.Append(strPatternSubst(CONSTLIT(" — %s-reflecting"), GetDamageShortName((DamageTypes)i)));
		}

	return sReference;
	}
Example #16
0
CString CDeviceClass::GetReference (CItemCtx &Ctx, int iVariant, DWORD dwFlags)

//	GetReference
//
//	Returns reference string

	{
	CString sReference;
	
	//	For a device we always add power and other properties.
	//	(If iVariant != -1 then it means that we're looking for reference on a
	//	missile or someting).
	
	if (iVariant == -1)
		{
		CInstalledDevice *pDevice = Ctx.GetDevice();

		//	Start with power requirements

		AppendReferenceString(&sReference, GetReferencePower(Ctx));

		//	Non-standard slots

		if (GetSlotsRequired() != 1)
			AppendReferenceString(&sReference, strPatternSubst(CONSTLIT("%d Slots"), GetSlotsRequired()));

		//	External devices

		if (IsExternal() || (pDevice && pDevice->IsExternal()))
			AppendReferenceString(&sReference, CONSTLIT("External"));
		}

	//	Combine with our subclass

	AppendReferenceString(&sReference, OnGetReference(Ctx, iVariant, dwFlags));
	return sReference;
	}
Example #17
0
void CShieldClass::FireOnShieldDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	FireOnShieldDamage
//
//	Fire OnShieldDamage

	{
	SEventHandlerDesc Event;
	if (FindEventHandlerShieldClass(evtOnShieldDamage, &Event))
		{
		//	Setup arguments

		CCodeChainCtx CCCtx;
		CCCtx.SaveAndDefineSourceVar(ItemCtx.GetSource());
		CCCtx.SaveAndDefineItemVar(ItemCtx);

		CCCtx.DefineInteger(CONSTLIT("aArmorSeg"), Ctx.iSectHit);
		CCCtx.DefineSpaceObject(CONSTLIT("aCause"), Ctx.pCause);
		CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), Ctx.Attacker.GetObj());
		CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (Ctx.Attacker.GetObj() ? Ctx.Attacker.GetObj()->GetOrderGiver(Ctx.Attacker.GetCause()) : NULL));
		CCCtx.DefineVector(CONSTLIT("aHitPos"), Ctx.vHitPos);
		CCCtx.DefineInteger(CONSTLIT("aHitDir"), Ctx.iDirection);
		CCCtx.DefineInteger(CONSTLIT("aDamageHP"), Ctx.iDamage);
		CCCtx.DefineString(CONSTLIT("aDamageType"), GetDamageShortName(Ctx.Damage.GetDamageType()));
		CCCtx.DefineItemType(CONSTLIT("aWeaponType"), Ctx.pDesc->GetWeaponType());

		CCCtx.DefineInteger(CONSTLIT("aShieldHP"), Ctx.iHPLeft);
		CCCtx.DefineInteger(CONSTLIT("aShieldDamageHP"), Ctx.iShieldDamage);
		CCCtx.DefineInteger(CONSTLIT("aArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb);
		if (Ctx.bReflect)
			{
			CCCtx.DefineString(CONSTLIT("aShieldReflect"), STR_SHIELD_REFLECT);
			CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iOriginalShieldDamage);
			CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iOriginalAbsorb);
			}
		else
			{
			CCCtx.DefineNil(CONSTLIT("aShieldReflect"));
			CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iShieldDamage);
			CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb);
			}

		ICCItem *pResult = CCCtx.Run(Event);

		//	If we return Nil, then nothing

		if (pResult->IsNil())
			NULL;

		//	If an error, report it

		else if (pResult->IsError())
			ItemCtx.GetSource()->ReportEventError(ON_SHIELD_DAMAGE_EVENT, pResult);

		//	If we return a list, then modify variables

		else if (pResult->IsList())
			{
			//	A single value means we modified the damage to armor

			if (pResult->GetCount() == 1)
				{
				if (strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT))
					{
					Ctx.bReflect = true;
					Ctx.iAbsorb = Ctx.iDamage;
					Ctx.iShieldDamage = 0;
					}
				else
					{
					Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft));
					if (Ctx.bReflect)
						{
						Ctx.bReflect = false;
						Ctx.iAbsorb = Ctx.iOriginalAbsorb;
						}
					}
				}

			//	Two values mean we modified both damage to armor and shield damage

			else if (pResult->GetCount() == 2)
				{
				Ctx.bReflect = false;
				Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft));
				Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(1)->GetIntegerValue()));
				}

			//	Otherwise, we deal with reflection

			else
				{
				Ctx.bReflect = strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT);
				Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(1)->GetIntegerValue(), Ctx.iHPLeft));
				Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(2)->GetIntegerValue()));
				}
			}

		CCCtx.Discard(pResult);
		}
	}
Example #18
0
void CArmorClass::CalcDamageEffects (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	CalcDamageEffects
//
//	Initialize the damage effects based on the damage and on this armor type.

	{
	CSpaceObject *pSource = ItemCtx.GetSource();
	CInstalledArmor *pArmor = ItemCtx.GetArmor();

	//	Compute all the effects (if we don't have installed armor, then the 
	//	caller is responsible for setting this).

	if (pArmor)
		Ctx.iHPLeft = pArmor->GetHitPoints();

	//	Reflect

	Ctx.bReflect = (IsReflective(ItemCtx, Ctx.Damage) && Ctx.iDamage > 0);

	//	Disintegration

	int iDisintegration = Ctx.Damage.GetDisintegrationDamage();
	Ctx.bDisintegrate = (iDisintegration > 0 && !IsDisintegrationImmune(ItemCtx));

	//	Shatter

	int iShatter = Ctx.Damage.GetShatterDamage();
	if (iShatter)
		{
		//	Compute the threshold mass. Below this size, we shatter the object

		int iMassLimit = 10 * mathPower(5, iShatter);
		Ctx.bShatter = (pSource && pSource->GetMass() < iMassLimit);
		}
	else
		Ctx.bShatter = false;

	//	Blinding

	int iBlinding = Ctx.Damage.GetBlindingDamage();
	if (iBlinding && !IsBlindingDamageImmune(ItemCtx))
		{
		//	The chance of being blinded is dependent
		//	on the rating.

		int iChance = 4 * iBlinding * iBlinding * GetBlindingDamageAdj() / 100;
		Ctx.bBlind = (mathRandom(1, 100) <= iChance);
		Ctx.iBlindTime = Ctx.iDamage * g_TicksPerSecond / 2;
		}
	else
		Ctx.bBlind = false;

	//	EMP

	int iEMP = Ctx.Damage.GetEMPDamage();
	if (iEMP && !IsEMPDamageImmune(ItemCtx))
		{
		//	The chance of being paralyzed is dependent
		//	on the EMP rating.

		int iChance = 4 * iEMP * iEMP * GetEMPDamageAdj() / 100;
		Ctx.bParalyze = (mathRandom(1, 100) <= iChance);
		Ctx.iParalyzeTime = Ctx.iDamage * g_TicksPerSecond / 2;
		}
	else
		Ctx.bParalyze = false;

	//	Device disrupt

	int iDeviceDisrupt = Ctx.Damage.GetDeviceDisruptDamage();
	if (iDeviceDisrupt && !IsDeviceDamageImmune(ItemCtx))
		{
		//	The chance of damaging a device depends on the rating.

		int iChance = 4 * iDeviceDisrupt * iDeviceDisrupt * GetDeviceDamageAdj() / 100;
		Ctx.bDeviceDisrupt = (mathRandom(1, 100) <= iChance);
		Ctx.iDisruptTime = 2 * Ctx.iDamage * g_TicksPerSecond;
		}
	else
		Ctx.bDeviceDisrupt = false;

	//	Device damage

	int iDeviceDamage = Ctx.Damage.GetDeviceDamage();
	if (iDeviceDamage && !IsDeviceDamageImmune(ItemCtx))
		{
		//	The chance of damaging a device depends on the rating.

		int iChance = 4 * iDeviceDamage * iDeviceDamage * GetDeviceDamageAdj() / 100;
		Ctx.bDeviceDamage = (mathRandom(1, 100) <= iChance);
		}
	else
		Ctx.bDeviceDamage = false;

	//	Radiation

	int iRadioactive = Ctx.Damage.GetRadiationDamage();
	Ctx.bRadioactive = (iRadioactive > 0 && !IsRadiationImmune(ItemCtx));

	//	Some effects decrease damage

	if (iBlinding || iEMP)
		Ctx.iDamage = 0;
	else if (iDeviceDamage)
		Ctx.iDamage = Ctx.iDamage / 2;
	}
Example #19
0
EDamageResults CArmorClass::AbsorbDamage (CItemCtx &ItemCtx, SDamageCtx &Ctx)

//	AbsorbDamage
//
//	Handles getting hit by damage.
//
//	Returns damageNoDamage if all the damage was absorbed and no further processing is necessary
//	Returns damageDestroyed if the source was destroyed
//	Returns damageArmorHit if source was damage and further processing (destroy check) is needed
//
//	Sets Ctx.iDamage to the amount of hit points left after damage absorption.

	{
	CSpaceObject *pSource = ItemCtx.GetSource();
	CInstalledArmor *pArmor = ItemCtx.GetArmor();
	if (pSource == NULL || pArmor == NULL)
		return damageNoDamage;

	//	Compute all the effects (this initializes elements in Ctx).

	CalcDamageEffects(ItemCtx, Ctx);

	//	First give custom weapons a chance

	bool bCustomDamage = Ctx.pDesc->FireOnDamageArmor(Ctx);
	if (pSource->IsDestroyed())
		return damageDestroyed;

	//	Damage adjustment

	CalcAdjustedDamage(ItemCtx, Ctx);

	//	If the armor has custom code to deal with damage, handle it here.

	FireOnArmorDamage(ItemCtx, Ctx);
	if (pSource->IsDestroyed())
		return damageDestroyed;

	//	If this armor section reflects this kind of damage then
	//	send the damage on

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

	//	If this is a disintegration attack, then disintegrate the ship

	if (Ctx.bDisintegrate)
		{
		if (!pSource->OnDestroyCheck(killedByDisintegration, Ctx.Attacker))
			return damageNoDamage;

		pSource->Destroy(killedByDisintegration, Ctx.Attacker);
		return damageDestroyed;
		}

	//	If this is a shatter attack, see if the ship is destroyed

	if (Ctx.bShatter)
		{
		if (!pSource->OnDestroyCheck(killedByShatter, Ctx.Attacker))
			return damageNoDamage;

		pSource->Destroy(killedByShatter, Ctx.Attacker);
		return damageDestroyed;
		}

	//	If this is a paralysis attack and we've gotten past the shields
	//	then freeze the ship.

	if (Ctx.bParalyze)
		pSource->MakeParalyzed(Ctx.iParalyzeTime);

	//	If this is blinding damage then our sensors are disabled

	if (Ctx.bBlind)
		pSource->MakeBlind(Ctx.iBlindTime);

	//	If this attack is radioactive, then contaminate the ship

	if (Ctx.bRadioactive)
		pSource->OnHitByRadioactiveDamage(Ctx);

	//	If this is device damage, then see if any device is damaged

	if (Ctx.bDeviceDamage)
		pSource->OnHitByDeviceDamage();

	if (Ctx.bDeviceDisrupt)
		pSource->OnHitByDeviceDisruptDamage(Ctx.iDisruptTime);

	//	Create a hit effect. (Many weapons show an effect even if no damage was
	//	done.)

	Ctx.pDesc->CreateHitEffect(pSource->GetSystem(), Ctx);

	//	If no damage has reached us, then we're done

	if (Ctx.iDamage == 0 && !bCustomDamage)
		return damageNoDamage;

	//	Give source events a chance to change the damage before we
	//	subtract from armor.

	if (pSource->HasOnDamageEvent())
		{
		pSource->FireOnDamage(Ctx);
		if (pSource->IsDestroyed())
			return damageDestroyed;
		}

	//	Take damage

	if (Ctx.iDamage <= pArmor->GetHitPoints())
		{
		pArmor->IncHitPoints(-Ctx.iDamage);
		Ctx.iDamage = 0;
		}
	else
		{
		Ctx.iDamage -= pArmor->GetHitPoints();
		pArmor->SetHitPoints(0);
		}

	return damageArmorHit;
	}
Example #20
0
CString CArmorClass::GetReference (CItemCtx &Ctx, int iVariant)
	
//	GetReference
//
//	Returns a string that describes the basic attributes
//	of this armor.
//
//	Example:
//
//		30 hp; laser-resistant; impact-resistant

	{
	int i;
	CString sReference;

	//	Get modifications

	int iLevel = m_pItemType->GetLevel();
	const CItemEnhancement &Mods = Ctx.GetMods();

	//	Radiation 

	if (m_fRadiationImmune || Mods.IsRadiationImmune())
		{
		if (iLevel < RADIATION_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("radiation-immune"));
		}
	else if (iLevel >= RADIATION_IMMUNE_LEVEL)
		AppendReferenceString(&sReference, CONSTLIT("radiation-vulnerable"));

	//	If we're immune to blinding/EMP/device damage, then collapse
	//	it all under a single entry

	bool bCheckedBlind = false;
	bool bCheckedEMP = false;
	bool bCheckedDevice = false;

	if ((m_iBlindingDamageAdj == 0 || Mods.IsBlindingImmune())
			&& (m_iEMPDamageAdj == 0 || Mods.IsEMPImmune())
			&& (m_iDeviceDamageAdj < 100 || Mods.IsDeviceDamageImmune()))
		{
		if (iLevel < DEVICE_DAMAGE_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("ion effect-immune"));

		bCheckedBlind = true;
		bCheckedEMP = true;
		bCheckedDevice = true;
		}

	//	Collapse blind and EMP resistance

	else if ((m_iBlindingDamageAdj == 0 || Mods.IsBlindingImmune())
			&& (m_iEMPDamageAdj == 0 || Mods.IsEMPImmune()))
		{
		if (iLevel < EMP_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("blind-, EMP-immune"));

		bCheckedBlind = true;
		bCheckedEMP = true;
		}
	else if ((m_iBlindingDamageAdj < 100) && (iLevel < BLIND_IMMUNE_LEVEL)
			&& (m_iEMPDamageAdj < 100))
		{
		AppendReferenceString(&sReference, CONSTLIT("blind-, EMP-resistant"));

		bCheckedBlind = true;
		bCheckedEMP = true;
		}

	//	Otherwise, treat each separate
	//
	//	Blindness

	if (!bCheckedBlind)
		{
		if (m_iBlindingDamageAdj == 0 || Mods.IsBlindingImmune())
			{
			if (iLevel < BLIND_IMMUNE_LEVEL)
				AppendReferenceString(&sReference, CONSTLIT("blind-immune"));
			}
		else if (m_iBlindingDamageAdj < 100)
			{
			if (iLevel < BLIND_IMMUNE_LEVEL)
				AppendReferenceString(&sReference, CONSTLIT("blind-resistant"));
			else
				AppendReferenceString(&sReference, CONSTLIT("blind-vulnerable"));
			}
		else if (iLevel >= BLIND_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("blind-vulnerable"));
		}

	//	EMP

	if (!bCheckedEMP)
		{
		if (m_iEMPDamageAdj == 0 || Mods.IsEMPImmune())
			{
			if (iLevel < EMP_IMMUNE_LEVEL)
				AppendReferenceString(&sReference, CONSTLIT("EMP-immune"));
			}
		else if (m_iEMPDamageAdj < 100)
			{
			if (iLevel < EMP_IMMUNE_LEVEL)
				AppendReferenceString(&sReference, CONSTLIT("EMP-resistant"));
			else
				AppendReferenceString(&sReference, CONSTLIT("EMP-vulnerable"));
			}
		else if (iLevel >= EMP_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("EMP-vulnerable"));
		}

	//	Device damage

	if (!bCheckedDevice)
		{
		if (m_iDeviceDamageAdj < 100 || Mods.IsDeviceDamageImmune())
			{
			if (iLevel < DEVICE_DAMAGE_IMMUNE_LEVEL)
				AppendReferenceString(&sReference, CONSTLIT("device-protect"));
			}
		else if (iLevel >= DEVICE_DAMAGE_IMMUNE_LEVEL)
			AppendReferenceString(&sReference, CONSTLIT("device-vulnerable"));
		}

	//	Disintegration

	if (m_fDisintegrationImmune || Mods.IsDisintegrationImmune())
		AppendReferenceString(&sReference, CONSTLIT("disintegrate-immune"));

	//	Shatter

	if (IsShatterImmune(Ctx))
		AppendReferenceString(&sReference, CONSTLIT("shatter-immune"));

	//	Shield interference

	if (m_fShieldInterference || Mods.IsShieldInterfering())
		AppendReferenceString(&sReference, CONSTLIT("no-shields"));

	//	Photo repair

	if (m_fPhotoRepair || Mods.IsPhotoRegenerating())
		AppendReferenceString(&sReference, CONSTLIT("photo-repair"));

	//	Solar power

	if (m_fPhotoRecharge || Mods.IsPhotoRecharge())
		AppendReferenceString(&sReference, CONSTLIT("solar"));

	//	Regeneration

	if ((!m_Regen.IsEmpty() && !m_fPhotoRepair) || Mods.IsRegenerating())
		AppendReferenceString(&sReference, CONSTLIT("regenerate"));

	//	Decay

	if (!m_Decay.IsEmpty() || Mods.IsDecaying())
		AppendReferenceString(&sReference, CONSTLIT("decay"));

	//	Reflection

	for (i = 0; i < damageCount; i++)
		{
		if (m_Reflective.InSet((DamageTypes)i)
				|| (Mods.IsReflective() && Mods.GetDamageType() == i))
			AppendReferenceString(&sReference, strPatternSubst(CONSTLIT("%s-reflecting"), GetDamageShortName((DamageTypes)i)));
		}

	//	Done

	return sReference;
	}
Example #21
0
bool CDeviceClass::SetItemProperty (CItemCtx &Ctx, const CString &sName, ICCItem *pValue, CString *retsError)

//	SetItemProperty
//
//	Sets a device property. Subclasses should call this if they do not 
//	understand the property.

	{
	CCodeChain &CC = g_pUniverse->GetCC();

	//	Get the installed device. We need this to set anything.

	CInstalledDevice *pDevice = Ctx.GetDevice();
	if (pDevice == NULL)
		{
		*retsError = CONSTLIT("Item is not an installed device on object.");
		return false;
		}

	//	Figure out what to set

	if (strEquals(sName, PROPERTY_FIRE_ARC))
		{
		//	A value of nil means no fire arc (and no omni)

		if (pValue == NULL || pValue->IsNil())
			{
			pDevice->SetOmniDirectional(false);
			pDevice->SetFireArc(0, 0);
			}

		//	A value of "omnidirectional" counts

		else if (strEquals(pValue->GetStringValue(), PROPERTY_OMNIDIRECTIONAL))
			{
			pDevice->SetOmniDirectional(true);
			pDevice->SetFireArc(0, 0);
			}

		//	A single value means that we just point in a direction

		else if (pValue->GetCount() == 1)
			{
			int iMinFireArc = AngleMod(pValue->GetElement(0)->GetIntegerValue());
			pDevice->SetOmniDirectional(false);
			pDevice->SetFireArc(iMinFireArc, iMinFireArc);
			}

		//	Otherwise we expect a list with two elements

		else if (pValue->GetCount() >= 2)
			{
			int iMinFireArc = AngleMod(pValue->GetElement(0)->GetIntegerValue());
			int iMaxFireArc = AngleMod(pValue->GetElement(1)->GetIntegerValue());
			pDevice->SetOmniDirectional(false);
			pDevice->SetFireArc(iMinFireArc, iMaxFireArc);
			}

		//	Invalid

		else
			{
			*retsError = CONSTLIT("Invalid fireArc parameter.");
			return false;
			}
		}

	else if (strEquals(sName, PROPERTY_LINKED_FIRE_OPTIONS))
		{
		//	Parse the options

		DWORD dwOptions;
		if (!::GetLinkedFireOptions(pValue, &dwOptions, retsError))
			return false;

		//	Set

		pDevice->SetLinkedFireOptions(dwOptions);
		}

	else if (strEquals(sName, PROPERTY_POS))
		{
		//	Get the parameters. We accept a single list parameter with angle/radius/z.
		//	(The latter is compatible with the return of objGetDevicePos.)

		int iPosAngle;
		int iPosRadius;
		int iZ;
		if (pValue == NULL || pValue->IsNil())
			{
			iPosAngle = 0;
			iPosRadius = 0;
			iZ = 0;
			}
		else if (pValue->GetCount() >= 2)
			{
			iPosAngle = pValue->GetElement(0)->GetIntegerValue();
			iPosRadius = pValue->GetElement(1)->GetIntegerValue();

			if (pValue->GetCount() >= 3)
				iZ = pValue->GetElement(2)->GetIntegerValue();
			else
				iZ = 0;
			}
		else
			{
			*retsError = CONSTLIT("Invalid angle and radius");
			return false;
			}

		//	Set it

		pDevice->SetPosAngle(iPosAngle);
		pDevice->SetPosRadius(iPosRadius);
		pDevice->SetPosZ(iZ);
		}

	else if (strEquals(sName, PROPERTY_SECONDARY))
		{
		if (pValue == NULL || !pValue->IsNil())
			pDevice->SetSecondary(true);
		else
			pDevice->SetSecondary(false);
		}

	else
		{
		*retsError = strPatternSubst(CONSTLIT("Unknown item property: %s."), sName);
		return false;
		}

	return true;
	}