Would you believe it? There is a small bug in the Combat Odds calculator! Fortunately, it does not have anything to do with the spearmen-defeats-tank issue.
The bug can only occur when dealing with units that have a damage cap (eg. catapults, trebuchets, cannons etc.).
These units when attacking can never kill the defender - they must always withdraw. A catapult can not damage a unit past 25HP and a cannon can not damage a unit past 20HP.
The odd thing is, when these units can dish out damage such that the damage can end up exactly on the combatLimit after a hit, the attacking unit still has to deal one more blow before he is forced to withdraw.
For example, a catapult vs. a warrior in a forest will have a iDamageToDefender value of 25HP. This means each time the catapult wins a round the warrior will take 25HP of damage.
Now you might wonder to yourself, does the catapult need to hit the warrior three times or four times before it is forced to withdraw? According to the way combat is resolved, the answer is four times, but in the BtS odds calculator it is assumed only three times. This means the calculator overestimates the retreat odds.
To prove this is the case in-game, try setting up a bunch of catapults to attack warriors in separate forests. Do a bunch of such battles (maybe 10 battles). Check through the combat log and you will see sometimes the warrior took 3 blows of 25HP but was still able to deal another hit to the catapult. This proves they were still fighting while the warrior was on 25HP - the catapult's combat limit.
Note in these pictures the upper odds ("Retreat Odds") are those predicted by the game, the middle odds "Odds" are the odds of attacker winning a given round (this line was thanks to DanF), and the Withdraw Odds shown in green are what I have calculated using my method.
Another test can be done with cannons vs. cataphracts (both having str12.). The cannon has a combatLimit of 80HP so it cannot damage a cataphract below 20HP.
The game predicts retreat odds of 63.7%. However in this case the true retreat odds are exactly 50%.
I have verified the 50% odds with the WB with 185 battles giving 93:92 odds (very close to 50:50).
How do we fix this bug?
The error is in CvGameCoreUtils::getCombatOdds.
Fixed (I hope)
The reason this bug does not present problems in ordinary battles, is that normally when a unit is brought to 0HP it dies straight away. You never have to battle with a defender while the defender is sitting on 0HP! But if the cap is 25HP then you do have to battle the defender if he has just reached 25HP - it is only when you land a blow that would send him below 25HP you are forced to retreat.
I have not looked much further to see if this bug happens in other parts of the code but I don't think it does. Also, I would imagine this bug is present in all earlier versions and expansions.
This thread's second purpose is to give a sneak preview to the Advanced Combat Odds interface I'm making. I stumbled on this bug in the process.
The bug can only occur when dealing with units that have a damage cap (eg. catapults, trebuchets, cannons etc.).
These units when attacking can never kill the defender - they must always withdraw. A catapult can not damage a unit past 25HP and a cannon can not damage a unit past 20HP.
The odd thing is, when these units can dish out damage such that the damage can end up exactly on the combatLimit after a hit, the attacking unit still has to deal one more blow before he is forced to withdraw.
For example, a catapult vs. a warrior in a forest will have a iDamageToDefender value of 25HP. This means each time the catapult wins a round the warrior will take 25HP of damage.
Now you might wonder to yourself, does the catapult need to hit the warrior three times or four times before it is forced to withdraw? According to the way combat is resolved, the answer is four times, but in the BtS odds calculator it is assumed only three times. This means the calculator overestimates the retreat odds.
To prove this is the case in-game, try setting up a bunch of catapults to attack warriors in separate forests. Do a bunch of such battles (maybe 10 battles). Check through the combat log and you will see sometimes the warrior took 3 blows of 25HP but was still able to deal another hit to the catapult. This proves they were still fighting while the warrior was on 25HP - the catapult's combat limit.
Note in these pictures the upper odds ("Retreat Odds") are those predicted by the game, the middle odds "Odds" are the odds of attacker winning a given round (this line was thanks to DanF), and the Withdraw Odds shown in green are what I have calculated using my method.
Another test can be done with cannons vs. cataphracts (both having str12.). The cannon has a combatLimit of 80HP so it cannot damage a cataphract below 20HP.
The game predicts retreat odds of 63.7%. However in this case the true retreat odds are exactly 50%.
I have verified the 50% odds with the WB with 185 battles giving 93:92 odds (very close to 50:50).
How do we fix this bug?
The error is in CvGameCoreUtils::getCombatOdds.
Code:
iNeededRoundsAttacker = (std::max(0, pDefender->currHitPoints() - iDefenderHitLimit) + iDamageToDefender - [COLOR="Red"]1[/COLOR] ) / iDamageToDefender;
Fixed (I hope)
Code:
iNeededRoundsAttacker = (std::max(0, pDefender->currHitPoints() - iDefenderHitLimit) + iDamageToDefender - [B](((pAttacker->combatLimit())==GC.getMAX_HIT_POINTS())?1:0)[/B] ) / iDamageToDefender;
The reason this bug does not present problems in ordinary battles, is that normally when a unit is brought to 0HP it dies straight away. You never have to battle with a defender while the defender is sitting on 0HP! But if the cap is 25HP then you do have to battle the defender if he has just reached 25HP - it is only when you land a blow that would send him below 25HP you are forced to retreat.
I have not looked much further to see if this bug happens in other parts of the code but I don't think it does. Also, I would imagine this bug is present in all earlier versions and expansions.
This thread's second purpose is to give a sneak preview to the Advanced Combat Odds interface I'm making. I stumbled on this bug in the process.