Knighttime
Prince
- Joined
- Sep 20, 2002
- Messages
- 380
Greetings, fellow Civ Fanatics! I hope this lengthy post regarding the Civilization II combat logic is useful and interesting to you. Any feedback, comments, or corrections are welcome -- I'll do my best to answer any questions or update this information if necessary.
INTRODUCTION
"The Complete Civilization II Combat Guide v1.1" has long been the most complete documentation available regarding the inner workings of the Civ II combat formula. With the addition of the civ.scen.onInitiateCombat() function to Lua events in TOTPP 0.16, though, scenario designers now have direct visibility to the strength and firepower of both the attacker and defender for every battle, as determined by the game after applying all combat modifiers. This means that many of the numeric values and adjustments which previously could only be determined by educated guesses and extensive testing, can now be analyzed and known for certain with far less work. This inspired me to begin working through the contents of that guide, with a goal of verifying and/or expanding it.
Along the way, though, I received some very significant help. @TheNamelessOne himself was kind enough to review my first attempt at a complete set of battle logic documentation. By examining the code within the game itself, he was able to provide some clarifications, identify rules that were never previously known in the community, and even track down a bug. Thanks to his involvement, I feel as though we can be rather confident that the documentation posted here is truly complete and accurate -- although, as TNO pointed out, it's still possible that there are additional bugs in the battle logic which haven't been discovered yet. Furthermore, I take full responsibility for any errors or omissions, which shouldn't be considered as any type of shortcoming on his part.
I would like to provide a sincere thank you to everyone who contributed to the original Civilization II Combat Guide, especially Marquis de Sodaq (a.k.a. Sodak) as the primary author. Considering the painstaking effort required to put together those rules, by running many battle simulations, they are remarkably thorough and accurate. Then I owe a huge thank you to @TheNamelessOne, not only for creating TOTPP in the first place but specifically for his detailed analysis of the rules posted below. His contributions mean that the accuracy and completeness of this documentation far exceed what I could ever have assembled on my own.
APPROACH
In the title, I described this post as "v2.0 updates" to "The Complete Civilization II Combat Guide v1.1". To clarify, though, I'm not attempting here to replace the entirety of that document, but primarily to update and expand upon sections 2 and 3, "Unit Combat Factors" and "Adjustment Factors". The contents of all other sections seem to be correct, at least reasonably so and to the best of my knowledge and understanding.
Section 2 of the Combat Guide v1.1 states that there are four basic factors considered in the calculation of a combat result, although I believe it would be more clear to refer to six separate numbers. Two of them are the remaining Hit Point values of the attacking and defending units; these are not subject to any adjustment factors, and as a result will not be mentioned further in this post.
The documentation below is therefore divided into four sections, one for each of the remaining numbers, detailing all of the adjustment factors that are possible for each. This is intentionally a slightly different organizational approach than section 3 of the Combat Guide v1.1, which is arranged by concepts (some of which affect multiple numbers). For each adjustment factor, though, I have provided a reference to the corresponding entry in the Combat Guide v1.1 if one exists, using italicized blue text.
Units with an attack strength of 99 have special "nuclear strike" behavior, and normal combat logic does not apply. (This is documented in (3)(o) of the Combat Guide.) All of the information below concerns non-nuclear battles, in which the attack strength of the attacking unit is 98 or lower.
ATTACKER STRENGTH
ATTACKER FIREPOWER
DEFENDER STRENGTH
DEFENDER FIREPOWER
LUA IMPLEMENTATION
All of the above information relates to the base game of Civ II, and therefore should be relevant to MGE as well as TOT (except for the fixes and additions provided by TOTPP).
Given all of the above information, though, it is now possible to write Lua code that would exactly recreate the game's native battle logic. Including this code in a scenario's events would essentially give the designer carte blanche to add, modify, or delete any adjustment factors, by carefully editing the code. However, this brings up the topics of "helper functions" and how they could or should be utilized in such code. My efforts to write such code follow the framework I developed and utilized for my Medieval Millennium mod, and work well in that context, but wouldn't run (without modifications) in a scenario using Prof. Garfield's Lua Scenario Template. Would it be most valuable to provide code that was adapted and/or fully integrated into the LST? Or instead should the goal be to provide code that is truly framework-independent, and could be copied into any set of Lua events without requiring adaptations? @Prof. Garfield what are your thoughts about codifying these rules?
INTRODUCTION
"The Complete Civilization II Combat Guide v1.1" has long been the most complete documentation available regarding the inner workings of the Civ II combat formula. With the addition of the civ.scen.onInitiateCombat() function to Lua events in TOTPP 0.16, though, scenario designers now have direct visibility to the strength and firepower of both the attacker and defender for every battle, as determined by the game after applying all combat modifiers. This means that many of the numeric values and adjustments which previously could only be determined by educated guesses and extensive testing, can now be analyzed and known for certain with far less work. This inspired me to begin working through the contents of that guide, with a goal of verifying and/or expanding it.
Along the way, though, I received some very significant help. @TheNamelessOne himself was kind enough to review my first attempt at a complete set of battle logic documentation. By examining the code within the game itself, he was able to provide some clarifications, identify rules that were never previously known in the community, and even track down a bug. Thanks to his involvement, I feel as though we can be rather confident that the documentation posted here is truly complete and accurate -- although, as TNO pointed out, it's still possible that there are additional bugs in the battle logic which haven't been discovered yet. Furthermore, I take full responsibility for any errors or omissions, which shouldn't be considered as any type of shortcoming on his part.
I would like to provide a sincere thank you to everyone who contributed to the original Civilization II Combat Guide, especially Marquis de Sodaq (a.k.a. Sodak) as the primary author. Considering the painstaking effort required to put together those rules, by running many battle simulations, they are remarkably thorough and accurate. Then I owe a huge thank you to @TheNamelessOne, not only for creating TOTPP in the first place but specifically for his detailed analysis of the rules posted below. His contributions mean that the accuracy and completeness of this documentation far exceed what I could ever have assembled on my own.
APPROACH
In the title, I described this post as "v2.0 updates" to "The Complete Civilization II Combat Guide v1.1". To clarify, though, I'm not attempting here to replace the entirety of that document, but primarily to update and expand upon sections 2 and 3, "Unit Combat Factors" and "Adjustment Factors". The contents of all other sections seem to be correct, at least reasonably so and to the best of my knowledge and understanding.
Section 2 of the Combat Guide v1.1 states that there are four basic factors considered in the calculation of a combat result, although I believe it would be more clear to refer to six separate numbers. Two of them are the remaining Hit Point values of the attacking and defending units; these are not subject to any adjustment factors, and as a result will not be mentioned further in this post.
The documentation below is therefore divided into four sections, one for each of the remaining numbers, detailing all of the adjustment factors that are possible for each. This is intentionally a slightly different organizational approach than section 3 of the Combat Guide v1.1, which is arranged by concepts (some of which affect multiple numbers). For each adjustment factor, though, I have provided a reference to the corresponding entry in the Combat Guide v1.1 if one exists, using italicized blue text.
Units with an attack strength of 99 have special "nuclear strike" behavior, and normal combat logic does not apply. (This is documented in (3)(o) of the Combat Guide.) All of the information below concerns non-nuclear battles, in which the attack strength of the attacking unit is 98 or lower.
ATTACKER STRENGTH
- Labeled the "attackerDie" parameter in the Lua documentation for onInitiateCombat()
- Base value is the attack strength of the attacking unit (a.k.a. "attacker")
- This base value is multiplied by a fixed value of 8, as correctly documented in section 4 of the Combat Guide
- Insufficient moves remaining. If the attacker had less than 1 MP remaining when it initiated the attack, it receives a proportionate adjustment (penalty). For example, if a unit attacked with only 1/3 MP remaining, it would receive a x0.3333 adjustment (penalty). Not previously documented in the Combat Guide, although widely understood since the game generates a popup window whenever the human player attempts this action, asking them to confirm or cancel.
- Veteran. If the attacker has veteran status, it receives a x1.5 adjustment (bonus). Correctly documented in (3)(a).
- Partisans. If the attacker is unit type 9 (Partisans in the base game) and the defender has an attack value of 0, the attacker receives a x8 adjustment (bonus). Note that this is the only situation in which the attack value of the defender is ever relevant. Correctly documented in (3)(i).
- Paradrop. If the attacker has completed a paradrop operation on the current turn, it receives a x1.5 adjustment (bonus). Not previously documented.
- Sneak attack. If the attacker is conducting a sneak attack (i.e., breaking a Cease Fire or Peace Treaty) and the defender belongs to a tribe controlled by a human player, the attacker receives a x2 adjustment (bonus). Identified in (3)(m) but precise scope and bonus amount were previously unknown.
- Easiest level, human attacker. If the game's difficulty level is the easiest one, "Chieftain", and the attacker belongs to a tribe controlled by a human player, the attacker receives a x2 adjustment (bonus). Not previously documented.
- Easy levels, human defender. If the game's difficulty level is one of the two easiest, "Chieftain" or "Warlord", and the defender belongs to a tribe controlled by a human player, the attacker receives a x0.5 adjustment (penalty). Not previously documented.
- Barbarian attacker vs. All of the following adjustments apply only when the attacking unit belongs to tribe 0, the barbarians.
- Human defender. If the defender belongs to a tribe controlled by a human player, the barbarian attacker receives an adjustment based on the game's difficulty level. The adjustment may be less than 1 (i.e. a penalty), equal to 1 (no effect), or greater than 1 (i.e. a bonus) depending on that value. The adjustments are: Chieftain x0.25, Warlord x0.5, Prince x0.75, King x1, Emperor x1.25, Deity x1.5. Documented in (3)(n), although the implication there is that this adjustment is applied regardless of the tribe of the defender, when in fact it is only applied when the defender belongs to a human player.
- AI defender. If the defender belongs to a tribe controlled by an AI player, the barbarian attacker receives a x0.5 adjustment (penalty). Not previously documented, but correctly noted in a separate thread.
- Defender's only city. If the defender is located in the only city belonging to the defender's tribe, the barbarian attacker receives a x0 adjustment (full penalty) -- in other words, its attack strength is set to 0, rendering all other adjustments irrelevant. Not previously documented, but essentially noted correctly in a separate thread.
- Defender's capital city. If the defender is located in a city with the Palace improvement, but this is not the defender's only city, the barbarian attacker receives a x0.5 adjustment (penalty). Not previously documented; noted as an adjustment in a separate thread but with an incorrect formula.
- Defender with Great Wall. If the defender's tribe controls the Great Wall wonder and it has not expired, the attacker receives a x0.5 adjustment (penalty). Not previously documented in the Combat Guide, but understood in a general sense due to the description of the Great Wall wonder, which says, "Combat strength doubled against barbarians." Technically the attack strength is halved, rather than the defense strength being doubled.
- Great Wall vs. barbarian defender. If the attacker's tribe controls the Great Wall wonder and it has not expired, and the defender is a barbarian, the attacker receives a x2 adjustment (bonus). Not previously documented in the Combat Guide, but understood in a general sense due to the description of the Great Wall wonder, which says, "Combat strength doubled against barbarians."
ATTACKER FIREPOWER
- Labeled the "attackerPower" parameter in the Lua documentation for onInitiateCombat()
- Base value is the firepower of the attacking unit (a.k.a. "attacker")
- Shore bombardment. If the attacker's domain is 2 (Sea) and the defender's domain is 0 (Ground) then the attacker's firepower is set to 1 (potential penalty, if the attacker natively has a larger firepower value). Correctly documented in (3)(j).
- Caught in port. If the attacker's domain is 0 (Ground) or 1 (Air) and the defender's domain is 2 (Sea) and the defender is not located on an Ocean tile, then the attacker's firepower receives a x2 adjustment (bonus). Correctly documented in (3)(k).
DEFENDER STRENGTH
- Labeled the "defenderDie" parameter in the Lua documentation for onInitiateCombat()
- Base value is the defense strength of the defending unit (a.k.a. "defender")
- This base value is multiplied by a fixed value of 8, as correctly documented in section 4 of the Combat Guide
- Veteran. If the defender has veteran status, it receives a x1.5 adjustment (bonus). Correctly documented in (3)(a).
- Scrambling fighter vs. bomber. If the defender's domain is 1 (Air) and defender has the "Can attack air units (fighter)" flag and defender is located in a city, and the attacker's domain is 1 (Air) and the attacker's range is not equal to 1, then the defender receives a x4 adjustment (bonus). Correctly documented in (3)(h)(iii)(1).
- Scrambling fighter vs. fighter. If the defender's domain is 1 (Air) and defender has the "Can attack air units (fighter)" flag and defender is located in a city, and the attacker has the "Can attack air units (fighter)" flag, then the defender receives a x2 adjustment (bonus). Correctly documented in (3)(h)(iii)(2).
- Helicopter. If the defender's domain is 1 (Air) and its range is 0 (which gives it "Helicopter behavior"), and the attacker's role is 3 (Air Superiority), then the defender receives a x0.5 adjustment (penalty). Documented in (3)(h)(iii)(3), although the reference there is to an attack by a fighter; the check is actually for attackers with the "Air Superiority" role, not the "Can attack air units (fighter)" flag.
- The defender is eligible to receive only one of the following three adjustments, which are checked in the following order:
- City Walls. If the defender's domain is 0 (Ground) and the defender is located in a city that has the City Walls improvement (or currently receives the benefit of City Walls due to the Great Wall wonder), and the attacker's domain is 0 (Ground) and the attacker does not have the "Negates city walls (howitzer)" flag, then the defender receives a configurable adjustment. By default this is a x3 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "CityWallsDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(e) plus (3)(h)(i).
- Fortress. If the defender's domain is 0 (Ground) and the defender is located on a tile with the Fortress improvement, and the attacker's domain is 0 (Ground) or 2 (Sea) and the attacker does not have the "Negates city walls (howitzer)" flag, then the defender receives a configurable adjustment. By default this is a x2 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "FortressDefense" key. Documented, other than TOTPP support for a configurable adjustment, in (3)(c). However, the reference there excludes the fact that an attacker with the "Negates city walls (howitzer)" flag also negates the Fortress bonus, in addition to its more obvious ability to negate the City Walls bonus.
- Fortified. If the defender's domain is 0 (Ground) and the defender is Fortified, it receives a configurable adjustment. By default this is a x1.5 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "FortifyDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(b).
- Pikemen flag. If the defender has the "x2 on defense versus horse (pikemen)" flag, and the attacker's domain is 0 (Ground) and the attacking unit's hitpoints (when fully healthy) is 10 (which is entered as "1h" in Rules.txt) then:
- The final requirement is that the attacker has 2 movement points (MP), however there is a bug in this implementation. The game actually checks the MP that the attacking unit received at the beginning of its current turn, after the movement adjustment applied due its damage level or remaining hitpoints, rather than checking the MP of the attacking unit's type (i.e., the full MP the unit would receive when completely healthy). Thus an attacker with native 3 MP could sometimes trigger this defender bonus, if damage lowered its effective MP to 2; and an attacker with native 2 MP could sometimes fail to trigger this defender bonus, if damage lowered its effective MP below 2. TheNamelessOne has promised that TOTPP 0.17 (coming soon) will contain a fix for this bug and with that fix enabled, the implementation will then look at the MP of the attacking unit's type, making any damage previously received by the attacking unit irrelevant.
- If all criteria are met, the defender receives a x1.5 adjustment (bonus). Documented in (3)(h)(ii), however the requirement that the attacker has firepower equal to 1 is incorrect.
- AEGIS flag vs. missile. If the defender has the "x2 on defense versus air (AEGIS)" flag, and the attacker's domain is 1 (Air) and the attacker has the "Destroyed after attacking (missiles)" flag, then the defender receives a configurable adjustment. By default this is a x5 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "AegisVSMissileDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(h)(iv).
- AEGIS flag vs. other air. If the defender has the "x2 on defense versus air (AEGIS)" flag, and the attacker's domain is 1 (Air) and the attacker does not have the "Destroyed after attacking (missiles)" flag, then the defender receives a configurable adjustment. By default this is a x3 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "AegisVSAirDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(h)(iv).
- SDI Defense vs. missile. If the defender is located in a city that has the SDI Defense improvement, and the attacker's domain is 1 (Air) and the attacker has the "Destroyed after attacking (missiles)" flag, then the defender receives a configurable adjustment. By default this is a x2 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "SDIDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(l).
- SAM Missile Battery. If the defender is located in a city that has the SAM Missile Battery improvement, and the attacker's domain is 1 (Air), and either the attacker has the "Destroyed after attacking (missiles)" flag or the defender does not have the "Can attack air units (fighter)" flag, then the defender receives a configurable adjustment. By default this is a x2 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "SAMDefense" key. Correctly documented, other than TOTPP support for a configurable adjustment, in (3)(f) plus (3)(h)(iii)(4).
- Coastal Fortress. If the defender's domain is 0 (Ground) or 1 (Air) and the defender is located in a city with the "Coastal Fortress" improvement, and the attacker's domain is 2 (Sea), then the defender receives a configurable adjustment. By default this is a x2 adjustment (bonus) but TOTPP permits this to be modified in the @COSMIC2 section, using the "CoastalFortressDefense" key. Documented, other than TOTPP support for a configurable adjustment, in (3)(g). However, the reference there is to any unit defending a city, which is technically incorrect since defenders with domain 2 (Sea) are excluded.
- Terrain. This adjustment is the only one in which there may be two components which are added together, first, before the final result is multiplied alongside any and all other adjustments.
- Base terrain type. The defender receives an adjustment determined by the base terrain of the tile on which it is located. The amount of the adjustment is defined in the @TERRAIN section Rules.txt for each terrain type; it may be less than 1 (i.e. a penalty), equal to 1 (no effect), or greater than 1 (i.e. a bonus) depending on that value. Furthermore, TOTPP supports two additional configuration elements. If the defender's domain is 1 (Air) and the @COSMIC2 section contains the "TerrainDefenseForAir" key set to 0, then the adjustment is automatically equal to 1 (meaning the terrain has no effect). Similarly, if the defender's domain is 2 (Sea) and the @COSMIC2 section contains the "TerrainDefenseForSea" key set to 0, then the adjustment is automatically equal to 1 (meaning the terrain has no effect). Correctly documented in (3)(d)(i) through (iii), other than TOTPP support for suppressing the adjustment in certain situations. Also, the reference there implies that terrain factors are static and doesn't note that they are configurable for each terrain type, although this is widely known.
- River. If the tile on which the defender is located contains a river, the amount of the terrain adjustment is increased by 0.5 (as noted above, this is an addition that occurs as part of the calculation of the terrain adjustment, before it is multiplied with other adjustments). Note that the @COSMIC2 keys referenced in the previous point do not eliminate the river bonus. Correctly documented in (3)(d)(iv), except that a "%" sign should not be included near the end of the line.
- Barbarian defender. Both of the following adjustments apply only when the defender belongs to tribe 0, the barbarians.
- Archers. If the barbarian defender is unit type 4 (Archers in the base game), it receives a x0.5 adjustment (penalty). Documented in (3)(n), but the reference there is somewhat unclear as to the actual behavior. Also it incorrectly states that other barbarian units have normal defense values, since there is one further exception:
- Legion. If the barbarian defender is unit type 5 (Legion in the base game), and no human-controlled tribe has tech 39 (Iron Working in the base game), the defender receives a x0.5 adjustment (penalty). Not previously documented.
DEFENDER FIREPOWER
- Labeled the "defenderPower" parameter in the Lua documentation for onInitiateCombat()
- Base value is the firepower of the defending unit (a.k.a. "defender")
- Helicopter. If the defender's domain is 1 (Air) and its range is 0 (which gives it "Helicopter behavior"), and the attacker's role is 3 (Air Superiority), then the defender's firepower is set to 1 (potential penalty, if the defender natively has a larger firepower value). Documented in (3)(h)(iii)(3), although the reference there is to an attack by a fighter; the check is actually for attackers with the "Air Superiority" role, not the "Can attack air units (fighter)" flag.
- Shore bombardment. If the attacker's domain is 2 (Sea) and the defender's domain is 0 (Ground) then the defender's firepower is set to 1 (potential penalty, if the defender natively has a larger firepower value). Correctly documented in (3)(j).
- Caught in port. If the attacker's domain is 0 (Ground) or 1 (Air) and the defender's domain is 2 (Sea) and the defender is not located on an Ocean tile, then the defender's firepower is set to 1 (potential penalty, if the defender natively has a larger firepower value). Correctly documented in (3)(k).
- Submarine flag. If the defender has the "Submarine advantages/disadvantages" flag, then its firepower is set to 1 (potential penalty, if the defender natively has a larger firepower value). Not previously documented, but correctly noted in a separate thread.
LUA IMPLEMENTATION
All of the above information relates to the base game of Civ II, and therefore should be relevant to MGE as well as TOT (except for the fixes and additions provided by TOTPP).
Given all of the above information, though, it is now possible to write Lua code that would exactly recreate the game's native battle logic. Including this code in a scenario's events would essentially give the designer carte blanche to add, modify, or delete any adjustment factors, by carefully editing the code. However, this brings up the topics of "helper functions" and how they could or should be utilized in such code. My efforts to write such code follow the framework I developed and utilized for my Medieval Millennium mod, and work well in that context, but wouldn't run (without modifications) in a scenario using Prof. Garfield's Lua Scenario Template. Would it be most valuable to provide code that was adapted and/or fully integrated into the LST? Or instead should the goal be to provide code that is truly framework-independent, and could be copied into any set of Lua events without requiring adaptations? @Prof. Garfield what are your thoughts about codifying these rules?
Last edited: