We are re-implementing the code that calculates damage to the hit cell and surrounding cells of an ArmorGridAPI and resulting damage (without any other modifiers) to the hull for our Starsector
but do not quite know how it works and cannot find any reference implementation or a rigorous specification for one, so I have proposed one below. Is it exactly correct?
private static float getPooledArmor(
final int iHit,
final int jHit,
final ArmorGridAPI armorGrid,
) {
float pooledArmor = 0;
for (int i = 0; i < 5; i++)
for (int j = 0; i < 5; j++)
if ((i == 0 || i == 5) && (j == 0 || j == 5)) //skip corners
continue;
else if (i == 0 || i == 5 || j == 0 || j == 5) //edges contribute half value
pooledArmor += 0.5 * armorGrid.getArmorValue(iHit + i, jHit + j);
else //center 9 contribute full value
pooledArmor += armorGrid.getArmorValue(iHit + i, jHit + j);
return pooledArmor;
}
private static float getHullDamage(
final float damage,
final float pooledArmor,
final float armorRating,
final float minimumArmorFactorForHullDamageReduction
) {
return damage
* damage
/ (damage + Math.max(pooledArmor, armorRating * minimumArmorFactorForHullDamageReduction));
}
private static float getArmorDamage(
final boolean isBeam,
final float damage,
final float pooledArmor,
final float maxArmorDamageReductionFactor,
final DamageType damageType
) {
float hitStrengthAgainstArmor = damage * (isBeam ? 0.5f : 1);
switch (damageType) {
case KINETIC: hitStrengthAgainstArmor *= 0.5;
case HIGH_EXPLOSIVE: hitStrengthAgainstArmor *= 2;
case FRAGMENTAETION: hitStrengthAgainstArmor *= 0.25f;
}
return hitStrengthAgainstArmor
* Math.max(1 - maxArmorDamageReductionFactor,
hitStrengthAgainstArmor / (hitStrengthAgainstArmor + pooledArmor));
}
private static void damageArmorGrid(
final int iHit,
final int jHit,
final float armorDamage,
final ArmorGridAPI armorGrid
) {
for (int i = 0; i < 5; i++)
for (int j = 0; i < 5; j++)
if ((i == 0 || i == 5) && (j == 0 || j == 5)) //skip corners
continue;
else if (i == 0 || i == 5 || j == 0 || j == 5) //edges take half damage
armorGrid.setArmorValue(i, j, Math.max(0, armorGrid.getArmorValue(i,j) - 0.5 * armorDamage));
else //center 9 take full damage
armorGrid.setArmorValue(i, j, Math.max(0, armorGrid.getArmorValue(i,j) - armorDamage));
}
private static void applyDamage(
final boolean isBeam,
final int iHit,
final int jHit,
final float damage,
final float minimumArmorFactorForHullDamageReduction,
final float maxArmorDamageReductionFactor,
final DamageType damageType,
final ShipAPI ship
) {
final ArmorGridAPI armorGrid = ship.getArmorGrid();
//calculate damage
final float pooledArmor = getPooledArmor(armorGrid, iHit, jHit);
final float hullDamage = getHullDamage(damage, pooledArmor, armorGrid.getArmorRating(), minimumArmorFactorForHullDamageReduction);
final float armorDamage = getArmorDamage(isBeam, damage, pooledArmor, maxArmorDamageReductionFactor, damageType);
//apply damage
damageArmorGrid(iHit, jHit, armorDamage, armorGrid);
ship.setHitpoints(Math.max(ship.getHitpoints() - hullDamage, 0)); //obviously makes ship disappear rather than explode, but we don't care about that effect
}