Oh Mann, ich muss mir mal Luft machen! 
Dieses Kampfsystem kann sich nur jemand ausgedacht haben, der a) im Vollrausch und b) vom Weltenhass zerfressen war.
Kleine Kostprobe? 
if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Combat") < iDefenderOdds)
Das ist die Zeile, welche bestimmt, ob der Angreifer einen Treffer landet oder nicht. Wenn er keinen Treffer landet, trifft automatisch der Verteidiger. So gut, so sinnarm, aber das haben wir weiter oben ja schon alles besprochen.
Nun fragt sich natürlich, was genau sind denn die iDefenderOdds?
Dazu müssen wir uns die Funktion getDefenderCombatValues(.......) ansehen:
Code:
void CvUnit::getDefenderCombatValues(CvUnit& kDefender, const CvPlot* pPlot, int iOurStrength, int iOurFirepower, int& iTheirOdds, int& iTheirStrength, int& iOurDamage, int& iTheirDamage, CombatDetails* pTheirDetails) const
{
iTheirStrength = kDefender.currCombatStr(pPlot, this, pTheirDetails);
int iTheirFirepower = kDefender.currFirepower(pPlot, this);
FAssert((iOurStrength + iTheirStrength) > 0);
FAssert((iOurFirepower + iTheirFirepower) > 0);
iTheirOdds = ((GC.getDefineINT("COMBAT_DIE_SIDES") * iTheirStrength) / (iOurStrength + iTheirStrength));
int iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);
iOurDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
iTheirDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
}
Und da geht'sdann richtig los... 
Ich gehe von folgender Kombination aus:
Angreifer: Stärke 10, 87 Hitpoints (ist halt verwundet, die maximalen Hitpoints sind 100)
Verteidiger: Stärke 10, 73 Hitpoints (auch verwundet, maximale Hitpoints sind natürlich auch 100)
iTheirStrength ist in diesem Fall die Stärke des Verteidigers, die sich aus currCombatStr(...) ergibt.
maxCombatStr(...) kann ich hier nicht darstellen, das erstreckt sich über 200 Zeilen oder so ähnlich. Für einen Kampf ohne Verteidigungswerte des Geländes und ohne Beförderungen, ohne Eingrabung oder Stadtmauer, ohne Bonus gegen Indianer (schnauf... hab' ich was vergessen?) liefert die Funktion maxCombatStr jedoch die Basisstärke * 100 an currCombatStr zurück.
Das müsste dann also unter Zugrundelegung obiger Annahmen 10*100*73/100 sein, also 7300.
Im nächsten Schritt wird dann iTheirFirePower errechnet. Dazu bedarf es der Funktion currFirepower(...)
Das ist dann also (maxCombatStr + currCombatStr +1)/2
(10000 + 7300 + 1)/2 = 8650,5
Das nehmen wir für den Moment mal kommentarlos so hin, auch wenn die Formel als wenig schlüssig erscheint. Tatsächlich tut sie nur eins, nämlich im Falle verletzter Einheiten deren Stärke künstlich anzuheben.
Nun geht es endlich an die Wahrscheinlichkeiten.
COMBAT_DIE_SIDES ist 1000
Also:
1000 * 7300 / (8700+7300) = 456,25 oder mit anderen Worten: der Verteidiger hat eine Wahrscheinlichkeit von ~45,625%, nicht getroffen zu werden und damit selbst zu treffen.
Das waren die Wahrscheinlichkeiten. Nun geht es um die Schadenspunkte, die dem einen oder dem anderen verpasst werden:
Dazu wird zunächst der iStrengthFactor berechnet:
(8700 + 7300 +1) / 2 = 8000,5 Es handelt sich hier um einen Integerwert, also 8000
Der Schaden, den der Angreifer erleidet, wenn er nicht trifft (p=0,45625), errechnet sich dann also folgendermaßen:
iOurDamage => der größere Wert von 1 oder 20 * (8650+8000)/(9350+8000) = 19,193... => 19
iTheirDamage => der größere Wert von 1 oder 20 * (9350+8000)/(8650+8000)= 20,84..... => 20
Würde man das Ganze ohne die currFirePower und ohne iStrenghtFactor, sondern nur aufgrund der Stärken berechnen, ergäbe sich
iOurDamage = 16,78 => 16
iTheirDamage = 23,83 => 23
Der Witz daran ist, dass die entweder 19/16 oder 20/23 Schadenspunkte aber von den Hitpoints noch abgezogen werden.
Tatsächlich muss der Angreifer im vorliegenden Fall "bei Colonization" noch 5mal, bei der "einfachen" Variante noch 6mal getroffen werden.
Der Verteidiger hingegen muss "bei Colonization" 4mal getroffen werden, bei der "einfachen" Variante auch viermal.
Die ganze Herumspielerei mit FirePower und StrengthFactor hat also m.E. nur das Ziel, den jeweiligen Verteidiger zu bevorteilen, kostet dafür aber Rechenzeit. Ob das sinnvoll ist, wage ich im Moment noch zu bezweifeln.
Ich werde mir mal überlegen, ob ich das nicht in meiner Mod einfach rauskegele... 
Und wenn ich mir die Zahlen so ansehe, dann frage ich mich, ob man nicht einfach COMBAT_DAMAGE (20) mit der Wahrscheinlichkeit mal 2 multiplizieren sollte (für den Verteidiger: p=0,45625 *2), um die notwendigen Treffer zu berechnen. Das würde dann 18 Schadenspunkte beim Angreifer ergeben und 21 beim Verteidiger, wäre viel kürzer und schneller zu berechnen und macht auf den ersten Blick keinen großen Unterschied aus. Muss ich morgen in einer stillen Stunde noch mal mit einigen anderen Werten durchrechnen ....