Zumindest in dem von PAE.
Aber Vodka ist doch super dafür? Grad 1 gegen 1. Da hat man keine Probleme mit der richtigen Reihenfolge^^ Einfach 1000 oder 10000 Durchläufe einstellen und man kommt sehr exakt ran^^
Zumindest in dem von PAE.
Aber Vodka ist doch super dafür? Grad 1 gegen 1. Da hat man keine Probleme mit der richtigen Reihenfolge^^ Einfach 1000 oder 10000 Durchläufe einstellen und man kommt sehr exakt ran^^
Im BtS-WB gibt es meines Wissens keine Funktion für die Trefferpunkte, man kann aber (außerhalb des WBs), wenn man CheatCode = chipotle aktiviert hat, zumindest die Trefferpunkte einer Einheit mit [Shift + ß] bzw. [Shift + ´] um 10 erhöhen/senken (ist je nachdem natürlich zu ungenau). Näheres hier (am Ende die Befehle und in der Mitte das mit chipotle, der Rest dreht sich größtenteils um die geschickte Verwendung der Kamera, also irrelevant).
Für MP-Spiele hat die ini-Änderung btw keine Bedeutung, die Funktionen sind dann einfach deaktiviert.
Tausendundein farukanische Nächte: Ein Splittermond-Abenteuer.
Das dachte ich ja auch. Aber in dem Einheitenmenü kann man nur Erfahrungspunkte und Stufen (unabhängig voneinander) und zusätzlich noch einzelne Beförderungen (ebenso unabhängig
) einstellen. Und der Einheit nen Namen geben. Das wars.
Daher seh ich das inzwischen so wie...
Das geht, keine Frage. Aber für jemanden wie mich, der immer auf seine Werkzeuge schaut ist das alles andere als Befriedigend.
Vodka betreibt Zulan auf eigene Rechnung auf seinem Server. Das heißt, wenn ich da was anfrage, dann kostet das Zulans server Rechenkapazität. Da einfach die Iterationen hochzusetzen ist meiner Meinung nach schon ziemlich unhöflich. Bei 10.000 Iterationen grenzt das ja schon fast an ne DOS-Attacke.Wenn das jeder täte...
Erschwerend kommt dazu, dass wir da immer sonen Simulationswust loslassen, sprich Strom, Rechenkapazität und Netzauslastung (jaja) ect. verbrauchen für etwas, was sich ganz simpel per Baumdiagramm ausrechnen lässt. Will heißen es ist auch noch völlig unnötig. Bei 20 gegen 20 Einheiten - und dafür ist Vodka ja eigentlich gedacht - ist das dann nicht mehr praktikabel ist. N Baumdiagramm ist übrigens nicht mal die Ideallösung, wie ich inzwischen festgestellt habe...
Vielen Dank für den Workaround.Aber
Also mein Kampfrechner ist jetzt in seiner ersten Betaversion fertig. Ich kann keine Erstangriffe. Das wird nochmal n Stück Arbeit, Obwohl es eigentlich gar nicht soooo schwer sein dürfte. Die Form ist jedenfalls ziemlich ideal für Erstangriffe, wenn ich so drüber nachdenke. Das Problem: Axt gegen Axt komme ich auf 87% Siegchance.Was ja nicht sein kann. Ist aber nicht schlimm. Ich gehe mal davon aus, dass ich die Kampfregeln so frei Schnauze nicht richtig implementiert habe. Ich muss also nochmal ne Wiki lesensuchen. Oder kennt jemand nen Link?
![]()
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Ab einer gewissen Baumgröße ist Monte Carlo einfach effizienterUnd ich hab für so einen Fall auch schonmal Zulan angefragt gehabt, das macht ihm nix. Meistens idlet so ein Server eh vor sich hin, die Zyklen kosten wirklich hinreichend nix im Verhältnis zu den Fixkosten, auch ökologsch.
Kampf-Link: http://www.civfanatics.com/civ4/stra..._explained.php
Thx. Das hab ich auch gefunden. Ich scheine aber alles richtig gemacht zu haben, außer die Berechnung des Rundenschadens. Der ist eh mal wieder so n Beispiel für ......
Hmm wenn ich den Einsetze komme ich auf 78%.
Ach die Phalanx hatte gar nicht 94, sondern nur 93 HPs. Damit komme ich auf 76,6 statt 76,1% was ziemlich sicher nur noch ein Rundungsfehler ist. Achtung, Das ist die Testrechnung mit meiner Sandkastenphalanx, nicht unbedingt wie im echten Spiel!
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Soooooo muss gleich weg. Daher reichts nur für n Pic vom Kampfrechner, nicht für das Dokument selbst.
So schauts aus. Schön ist, das bei der Form auch automatisch rauskommt, wie hoch die Chancen sind mit 1, 2 usw. verlorenen Kämpfen zu Siegen. Wer scharfe Augen hat (und das Dokument versteht) kann dementsprechend sehen, dass wir mit 20% gar keinen und mit weiteren 23% nur 17 zusätzlichen Schaden davontragen. Dies zumindest fand ich erstaunlich.
![]()
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Achja, bevor ichs vergesse... ich würde gerne SPA...
ein WKII-Upgrade spendieren und dann 2-3/4-(9?) ziehen.
Alles andere wie gehabt. Bist du mit den MM-Plänen gerade vertraut? T45 steht an:
WBF muss die Straße auf dem EH abschließen.
BMF soll die Straße 1 vom Reis anbauen, also danach abbrechen. Phalanx begleitet. achja die braucht noch nen Nahmen, aber der kann wohl auch warten.
Siedler zieht auf den Reis.
Ich würd dem Krieger gerne ein Saniupgrade spendieren, und weiter heilen lassen.
PTA auf Wald -> Kriegserklärung an Karthago sollte klar sein.
Wir sollten halt nächsten Zug so schnell wie möglich angehen. Sprich wer schneller drin ist zieht. Hat den einfachen Hintergrund, das Karthago sonst einen Zug mehr bekommt, um die Stadt zu sichern... Nicht das es sonderlich wichtig wäre, solange wir den 75-80% Kampf riskieren wollen. 2 Einheiten bekommt der da nie und nimmer so schnell rein.![]()
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Danke für die AnleitungIch werd mal sehen, wie ich morgen Nachmittag Zeit hab. Ich versuch es einzurichten.
Soooo Zug erledigt. Krieg erklärt. Ich hab ne PM an Simon und alle Schiris geschickt. Ich hoffe, es war der richtige Simon. Da gab es ein paar zur Auswahl.
Was noch. Also erstens nerfen die Malis.
Dann gabs im Osten noch viel mehr Tierfutter.
Wir sind noch nichtmal mehr die einzigen die Utica plündern wollen. :o
Außerdem hab ich aktuell mal das Städteranking geschossen, weil...
da sowohl Frankreich als auch Karthago auftauchen.Was machen die denn.
Und was noch wichtig war - Strom - wir sind übrigens nach wie vor 3.
Ari und Malis haben Spass. Das ist fein.
Ich wollte eigentlich noch das Log schießen, aber das hab ich vergessen. Naja, nächste Runde ist auch noch ne Runde.![]()
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Also Vodka darf ruhig benutzt werden. Ich hab ein paar primitive sperren gegen zu lange Berechnungen drin.
Fuer 2 Einheiten gibt es bereits einen kompletten Code zur Berechnung der Kampfchancen. Naemlich aus Civ4 selbst:
Sogar mit KommentarenCode:// FUNCTION: getCombatOdds // Calculates combat odds, given two units // Returns value from 0-1000 // Written by DeepO int getCombatOdds(CvUnit* pAttacker, CvUnit* pDefender) { float fOddsEvent; float fOddsAfterEvent; int iAttackerStrength; int iAttackerFirepower; int iDefenderStrength; int iDefenderFirepower; int iDefenderOdds; int iAttackerOdds; int iStrengthFactor; int iDamageToAttacker; int iDamageToDefender; int iNeededRoundsAttacker; int iNeededRoundsDefender; int iMaxRounds; int iAttackerLowFS; int iAttackerHighFS; int iDefenderLowFS; int iDefenderHighFS; int iFirstStrikes; int iDefenderHitLimit; int iI; int iJ; int iI3; int iI4; int iOdds = 0; // setup battle, calculate strengths and odds ////// //Added ST iAttackerStrength = pAttacker->currCombatStr(NULL, NULL); iAttackerFirepower = pAttacker->currFirepower(NULL, NULL); iDefenderStrength = pDefender->currCombatStr(pDefender->plot(), pAttacker); iDefenderFirepower = pDefender->currFirepower(pDefender->plot(), pAttacker); FAssert((iAttackerStrength + iDefenderStrength) > 0); FAssert((iAttackerFirepower + iDefenderFirepower) > 0); iDefenderOdds = ((GC.getDefineINT("COMBAT_DIE_SIDES") * iDefenderStrength) / (iAttackerStrength + iDefenderStrength)); if (iDefenderOdds == 0) { return 1000; } iAttackerOdds = GC.getDefineINT("COMBAT_DIE_SIDES") - iDefenderOdds; if (iAttackerOdds == 0) { return 0; } iStrengthFactor = ((iAttackerFirepower + iDefenderFirepower + 1) / 2); // calculate damage done in one round ////// iDamageToAttacker = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iDefenderFirepower + iStrengthFactor)) / (iAttackerFirepower + iStrengthFactor))); iDamageToDefender = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iAttackerFirepower + iStrengthFactor)) / (iDefenderFirepower + iStrengthFactor))); // calculate needed rounds. // Needed rounds = round_up(health/damage) ////// iDefenderHitLimit = pDefender->maxHitPoints() - pAttacker->combatLimit(); iNeededRoundsAttacker = (std::max(0, pDefender->currHitPoints() - iDefenderHitLimit) + iDamageToDefender - 1 ) / iDamageToDefender; iNeededRoundsDefender = (pAttacker->currHitPoints() + iDamageToAttacker - 1 ) / iDamageToAttacker; iMaxRounds = iNeededRoundsAttacker + iNeededRoundsDefender - 1; // calculate possible first strikes distribution. // We can't use the getCombatFirstStrikes() function (only one result, // no distribution), so we need to mimic it. ////// iAttackerLowFS = (pDefender->immuneToFirstStrikes()) ? 0 : pAttacker->firstStrikes(); iAttackerHighFS = (pDefender->immuneToFirstStrikes()) ? 0 : (pAttacker->firstStrikes() + pAttacker->chanceFirstStrikes()); iDefenderLowFS = (pAttacker->immuneToFirstStrikes()) ? 0 : pDefender->firstStrikes(); iDefenderHighFS = (pAttacker->immuneToFirstStrikes()) ? 0 : (pDefender->firstStrikes() + pDefender->chanceFirstStrikes()); // For every possible first strike event, calculate the odds of combat. // Then, add these to the total, weighted to the chance of that first // strike event occurring ////// for (iI = iAttackerLowFS; iI < iAttackerHighFS + 1; iI++) { for (iJ = iDefenderLowFS; iJ < iDefenderHighFS + 1; iJ++) { // for every possible combination of fs results, calculate the chance if (iI >= iJ) { // Attacker gets more or equal first strikes than defender iFirstStrikes = iI - iJ; // For every possible first strike getting hit, calculate both // the chance of that event happening, as well as the rest of // the chance assuming the event has happened. Multiply these // together to get the total chance (Bayes rule). // iI3 counts the number of successful first strikes ////// for (iI3 = 0; iI3 < (iFirstStrikes + 1); iI3++) { // event: iI3 first strikes hit the defender // calculate chance of iI3 first strikes hitting: fOddsEvent // f(k;n,p)=C(n,k)*(p^k)*((1-p)^(n-k)) // this needs to be in floating point math ////// fOddsEvent = ((float)getBinomialCoefficient(iFirstStrikes, iI3)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI3) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), (iFirstStrikes - iI3)); // calculate chance assuming iI3 first strike hits: fOddsAfterEvent ////// if (iI3 >= iNeededRoundsAttacker) { fOddsAfterEvent = 1; } else { fOddsAfterEvent = 0; // odds for _at_least_ (iNeededRoundsAttacker - iI3) (the remaining hits // the attacker needs to make) out of (iMaxRounds - iI3) (the left over // rounds) is the sum of each _exact_ draw ////// for (iI4 = (iNeededRoundsAttacker - iI3); iI4 < (iMaxRounds - iI3 + 1); iI4++) { // odds of exactly iI4 out of (iMaxRounds - iI3) draws. // f(k;n,p)=C(n,k)*(p^k)*((1-p)^(n-k)) // this needs to be in floating point math ////// fOddsAfterEvent += ((float)getBinomialCoefficient((iMaxRounds - iI3), iI4)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI4) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), ((iMaxRounds - iI3) - iI4)); } } // Multiply these together, round them properly, and add // the result to the total iOdds ////// iOdds += ((int)(1000.0 * (fOddsEvent*fOddsAfterEvent + 0.0005))); } } else // (iI < iJ) { // Attacker gets less first strikes than defender iFirstStrikes = iJ - iI; // For every possible first strike getting hit, calculate both // the chance of that event happening, as well as the rest of // the chance assuming the event has happened. Multiply these // together to get the total chance (Bayes rule). // iI3 counts the number of successful first strikes ////// for (iI3 = 0; iI3 < (iFirstStrikes + 1); iI3++) { // event: iI3 first strikes hit the defender // First of all, check if the attacker is still alive. // Otherwise, no further calculations need to occur ///// if (iI3 < iNeededRoundsDefender) { // calculate chance of iI3 first strikes hitting: fOddsEvent // f(k;n,p)=C(n,k)*(p^k)*((1-p)^(n-k)) // this needs to be in floating point math ////// fOddsEvent = ((float)getBinomialCoefficient(iFirstStrikes, iI3)) * pow((((float)iDefenderOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI3) * pow((1.0f - (((float)iDefenderOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), (iFirstStrikes - iI3)); // calculate chance assuming iI3 first strike hits: fOddsAfterEvent ////// fOddsAfterEvent = 0; // odds for _at_least_ iNeededRoundsAttacker (the remaining hits // the attacker needs to make) out of (iMaxRounds - iI3) (the left over // rounds) is the sum of each _exact_ draw ////// for (iI4 = iNeededRoundsAttacker; iI4 < (iMaxRounds - iI3 + 1); iI4++) { // odds of exactly iI4 out of (iMaxRounds - iI3) draws. // f(k;n,p)=C(n,k)*(p^k)*((1-p)^(n-k)) // this needs to be in floating point math ////// fOddsAfterEvent += ((float)getBinomialCoefficient((iMaxRounds - iI3), iI4)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI4) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), ((iMaxRounds - iI3) - iI4)); } // Multiply these together, round them properly, and add // the result to the total iOdds ////// iOdds += ((int)(1000.0 * (fOddsEvent*fOddsAfterEvent + 0.0005))); } } } } } // Weigh the total to the number of possible combinations of first strikes events // note: the integer math breaks down when #FS > 656 (with a die size of 1000) ////// iOdds /= (((pDefender->immuneToFirstStrikes()) ? 0 : pAttacker->chanceFirstStrikes()) + 1) * (((pAttacker->immuneToFirstStrikes()) ? 0 : pDefender->chanceFirstStrikes()) + 1); // finished! ////// return iOdds; }.
Achtung Spoiler:
Also der Code ist für Excel schon n bissel unbrauchbar.
Immerhin konnt ich dem entnehmen, dass CIV die Chancen alle nach 3 Stellen abschneidet. Das lässt sich schwer abbilden. Stärkewerte kann ich abschneiden, aber wenn ich das bei Wahrscheinlichkeiten mache bekomme ich Schwierigkeiten, wenn sie sich zu 1 addieren sollen.Und im Endergebnis will ich ja genau das. Der Unterschied sind allerdings zum echten Kampf zehntelprozent. Das ist wohl verschmerzbar, und kommt ungefähr auf Vodka raus, wenn man ziemlich viele Durchläufe simuliert - nur ohne die Unsicherheit, weil mein Fehler systematischer Natur ist.
Und dann ist da was, was mich stutzig macht:
WTF?!? Was hat das im Kampfsystem zu suchen? Ich wills vermutlich gar nicht wissen.Code:iOdds += ((int)(1000.0 * (fOddsEvent*fOddsAfterEvent + 0.0005
Im Ernst. Es ist toll, das sich Leute mit diesem Kauderwelsch auseinandersetzen. Vielleicht bin ichs ja auch nicht gewohnt, aber ich staune jedes mal wie zusammengeflickt so ein Spielcode aussieht. Und dann diese Variablennamen.Ich fuchse mich sicherlich nicht durch diese 180 Zeilen.
Ich lese die Wicki und schreibe nen Seite Tabellen dazu. Ich brauche - mal abgesehen von so Formelkanonen wie a / b und Summe(Bereich) genau 3 Formeln mit denen ich 4 Tabellen erstelle:
1a. WENN(INDEX($C$18:$D$36;$F10;1)>0;ABRUNDEN(($C$9*INDEX($C$18:$D$36;$F10;1)*(100+$C$12)/10000);2);0) für die Stärkewerte des Angreifers
1b. ist nochmal das selbe, bloß mit anderen Feldern - nämlich die des Verteidigers.
2. ABRUNDEN(100*WENN(UND(H10=0;H32=0);0;H10/(H10+H32));1)
Die sehen ziemlich kompliziert aus. Das liegt aber mehr an den Wenn-Funktionen, mit denen ich meißt nur Werte unter 0 ausschließe oder division durch 0 verhindere, damit ich mit den Werten weiterarbeiten kann.Ohne die sehen die Formeln so aus.
1a. EinheitenGrundstärke * aktuelle HP / 100 * (100+Kampfboni)/100 auf 2 Stellen nach dem Komma gerundet - die Stärke bei unterschiedlichen HP
1b. wie gehabt
2. Stärke Angreifer * (Stärke Angreifer + Stärke Verteidiger) * 100 und dann auf eine Stelle gerundet - die Kampfchance
3. (H76*H54+I75*(100-I53))/100
Die steht so in der Tabelle. Und die gibt nichts weiter an, als die Wahrscheinlichkeit, dass am Ende des Kampfes der Angreifer X und der Verteidiger Y HPs haben, aufsummiert aus den Wahrscheinlichkeiten, dass der Angreifer X+x hatte (in der Spalte links) und einen Kampf verliert und das der Verteidiger Y+y hatte (in der Zeile obendrüber) und einen Kampf verliert. Das ist der eigentliche Clou, der das ganze mit Excel super beherrschbar macht.
Diese 3 Formeln sind nicht so wahnsinnig kompliziert.
Damit erstelle ich 4 Tabellen. 2 mit den möglichen Kampfstärken jeweils des Angreifers und des Verteidigers, eine mit den Kampfchancen bei dem entsprechenden Kampf, und eine die aus den Einzelkampfchancen quasi den Baum abbildet (aber eben als Tabelle).
Dazu kommen, wenn ich dann Lust habe nochmal paar n über ks, für die Erstangriffe - das wäre dann wirklich die Highendmathe, die ich brauchen werde. Und die fallen dann wie von selbst in die Randbedingungen meiner 4. Tabelle - die mit den Ergebnissen.
Kann sein, dass es daran liegt, dass ich gerne solche Sheets bastle, aber ich find das viel einfacher, als den Code auch nur nachzuvollziehen.![]()
Geändert von ComCitCat (07. Februar 2015 um 23:32 Uhr)
Alice Schwarzer hat sich neulich zu den Corona-Maßnahmen positioniert.
Zitat von Alice Schwarzer
Hast du ein Foto von unserer Phalanx vor der karthagischen Stadt geschossen? Und ist die immer noch leer?
...also, das mit den +0.0005 sieht für mich nach "ich will echt runden und nicht immer abrunden, deshalb rechne ich +0.0005 und runde dann auf ganze Tausendstel ab" aus. Ich war jetzt aber auch zu faul, den Code durchzulesen.
Mit Naturgesetzen kann man nicht verhandeln. --Harald Lesch
Ein Atomkrieg würde die Menschheit auslöschen. Hätte aber auch Nachteile.
Also dieser Code im Speziellen besteht fast nur aus Kommentaren und Deklarationen. Ohne schauts so aus, und ja, das meiste ist Erstschlagsberechnung:
Code:int getCombatOdds(CvUnit* pAttacker, CvUnit* pDefender) { iAttackerStrength = pAttacker->currCombatStr(NULL, NULL); iAttackerFirepower = pAttacker->currFirepower(NULL, NULL); iDefenderStrength = pDefender->currCombatStr(pDefender->plot(), pAttacker); iDefenderFirepower = pDefender->currFirepower(pDefender->plot(), pAttacker); FAssert((iAttackerStrength + iDefenderStrength) > 0); FAssert((iAttackerFirepower + iDefenderFirepower) > 0); iDefenderOdds = ((GC.getDefineINT("COMBAT_DIE_SIDES") * iDefenderStrength) / (iAttackerStrength + iDefenderStrength)); if (iDefenderOdds == 0) { return 1000; } iAttackerOdds = GC.getDefineINT("COMBAT_DIE_SIDES") - iDefenderOdds; if (iAttackerOdds == 0) { return 0; } iStrengthFactor = ((iAttackerFirepower + iDefenderFirepower + 1) / 2); iDamageToAttacker = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iDefenderFirepower + iStrengthFactor)) / (iAttackerFirepower + iStrengthFactor))); iDamageToDefender = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iAttackerFirepower + iStrengthFactor)) / (iDefenderFirepower + iStrengthFactor))); iDefenderHitLimit = pDefender->maxHitPoints() - pAttacker->combatLimit(); iNeededRoundsAttacker = (std::max(0, pDefender->currHitPoints() - iDefenderHitLimit) + iDamageToDefender - 1 ) / iDamageToDefender; iNeededRoundsDefender = (pAttacker->currHitPoints() + iDamageToAttacker - 1 ) / iDamageToAttacker; iMaxRounds = iNeededRoundsAttacker + iNeededRoundsDefender - 1; iAttackerLowFS = (pDefender->immuneToFirstStrikes()) ? 0 : pAttacker->firstStrikes(); iAttackerHighFS = (pDefender->immuneToFirstStrikes()) ? 0 : (pAttacker->firstStrikes() + pAttacker->chanceFirstStrikes()); iDefenderLowFS = (pAttacker->immuneToFirstStrikes()) ? 0 : pDefender->firstStrikes(); iDefenderHighFS = (pAttacker->immuneToFirstStrikes()) ? 0 : (pDefender->firstStrikes() + pDefender->chanceFirstStrikes()); for (iI = iAttackerLowFS; iI < iAttackerHighFS + 1; iI++) { for (iJ = iDefenderLowFS; iJ < iDefenderHighFS + 1; iJ++) { if (iI >= iJ) { iFirstStrikes = iI - iJ; for (iI3 = 0; iI3 < (iFirstStrikes + 1); iI3++) { fOddsEvent = ((float)getBinomialCoefficient(iFirstStrikes, iI3)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI3) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), (iFirstStrikes - iI3)); if (iI3 >= iNeededRoundsAttacker) { fOddsAfterEvent = 1; } else { fOddsAfterEvent = 0; for (iI4 = (iNeededRoundsAttacker - iI3); iI4 < (iMaxRounds - iI3 + 1); iI4++) { fOddsAfterEvent += ((float)getBinomialCoefficient((iMaxRounds - iI3), iI4)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI4) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), ((iMaxRounds - iI3) - iI4)); } } iOdds += ((int)(1000.0 * (fOddsEvent*fOddsAfterEvent + 0.0005))); } } else { iFirstStrikes = iJ - iI; for (iI3 = 0; iI3 < (iFirstStrikes + 1); iI3++) { if (iI3 < iNeededRoundsDefender) { fOddsEvent = ((float)getBinomialCoefficient(iFirstStrikes, iI3)) * pow((((float)iDefenderOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI3) * pow((1.0f - (((float)iDefenderOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), (iFirstStrikes - iI3)); fOddsAfterEvent = 0; for (iI4 = iNeededRoundsAttacker; iI4 < (iMaxRounds - iI3 + 1); iI4++) { fOddsAfterEvent += ((float)getBinomialCoefficient((iMaxRounds - iI3), iI4)) * pow((((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES")), iI4) * pow((1.0f - (((float)iAttackerOdds) / GC.getDefineINT("COMBAT_DIE_SIDES"))), ((iMaxRounds - iI3) - iI4)); } iOdds += ((int)(1000.0 * (fOddsEvent*fOddsAfterEvent + 0.0005))); } } } } } iOdds /= (((pDefender->immuneToFirstStrikes()) ? 0 : pAttacker->chanceFirstStrikes()) + 1) * (((pAttacker->immuneToFirstStrikes()) ? 0 : pDefender->chanceFirstStrikes()) + 1); return iOdds;