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; }
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; }
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; }
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; }
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; }
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; }