bool CShieldClass::GetReferenceDamageAdj (const CItem *pItem, CSpaceObject *pInstalled, int *retiHP, int *retArray) const // GetReferenceDamageAdj // // Returns an array of damage adj values { CItemCtx Ctx(pItem, pInstalled); int i; const CItemEnhancement &Mods = Ctx.GetMods(); int iMinHP, iMaxHP; CalcMinMaxHP(Ctx, m_iMaxCharges, 0, 0, &iMinHP, &iMaxHP); if (retiHP) *retiHP = iMaxHP; if (retArray) { for (i = 0; i < damageCount; i++) { DamageDesc Damage((DamageTypes)i, DiceRange(0, 0, 0)); int iAdj = GetDamageAdj(Mods, Damage); if (iAdj == 0) retArray[i] = -1; else retArray[i] = (int)((iMaxHP * 100.0 / iAdj) + 0.5); } } return true; }
int CArmorClass::CalcAverageRelativeDamageAdj (void) // CalcAverageRelativeDamageAdj // // Compares this armor against standard damage adj for the level and returns // the average damage adj relative to the standard. { int i; Metric rTotalAdj = 0.0; int iCount = 0; int iArmorLevel = m_pItemType->GetLevel(); for (i = damageLaser; i < damageCount; i++) { // If this damage type is within two levels of the armor level, // then we include it in our calculations. int iDamageLevel = ::GetDamageTypeLevel((DamageTypes)i); if (iArmorLevel < iDamageLevel + 5 && iArmorLevel > iDamageLevel - 3) { int iStdAdj = GetStdDamageAdj(iArmorLevel, (DamageTypes)i); int iDamageAdj = GetDamageAdj((DamageTypes)i); rTotalAdj += (iStdAdj > 0.0 ? (Metric)iDamageAdj * 100.0 / iStdAdj : 1000.0); iCount++; } } // Return average return (iCount > 0 ? (int)((rTotalAdj / iCount) + 0.5) : 100); }
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; }
bool CArmorClass::GetReferenceDamageAdj (const CItem *pItem, CSpaceObject *pInstalled, int *retiHP, int *retArray) // GetReferenceDamageAdj // // Returns armor HP after adjustment for damage type { int i; CItemCtx ItemCtx(pItem, pInstalled); int iHP = GetMaxHP(ItemCtx); if (retiHP) *retiHP = iHP; for (i = 0; i < damageCount; i++) { DamageDesc Damage((DamageTypes)i, DiceRange(0, 0, 0)); int iAdj = GetDamageAdj(ItemCtx.GetMods(), Damage); if (retArray) retArray[i] = CalcHPDamageAdj(iHP, iAdj); } return true; }
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 CArmorClass::GetDamageAdj (CItemEnhancement Mods, const DamageDesc &Damage) // GetDamageAdj // // Returns the damage adjustment for the given damage type { int iDamageAdj = GetDamageAdj(Damage.GetDamageType()); if (Mods.IsNotEmpty()) return iDamageAdj * Mods.GetDamageAdj(Damage) / 100; else return iDamageAdj; }
int CArmorClass::GetDamageAdjForWeaponLevel (int iLevel) // GetDamageAdjForWeaponLevel // // Returns the least effective damage adjustment of all damage types appropriate // to the given level. { int i; int iBestAdj = 0; for (i = 0; i < damageCount; i++) { if (CWeaponClass::IsStdDamageType((DamageTypes)i, iLevel)) { int iDamageAdj = GetDamageAdj((DamageTypes)i); if (iDamageAdj > iBestAdj) iBestAdj = iDamageAdj; } } return iBestAdj; }
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 }