@f1rpo On the limited defender set
Initially I wanted to create the set "on the fly", but I realized that hoovering over an enemy defender set in CvGameTextMgr::setCombatPlotHelp would lead to OOS issues. Sadly I did not realize at the time that your hash idea would have solved that!
So instead I then went ahead and implemented the following:
Maintain a defender set (i.e. vector) of available units per plot that is:
- Randomly generated on every turn i.e. CvPlot::doTurn() (As an alternative the list could be created at the end of every player's turn though)
- Regenerated \ updated any time CvUnit::setXY() resulted in a unit being added to or removed from the plot. If a unit died, the list would also be regenerated.
CvPlot::getBestDefender() was then changed to query the defender set rather than iterating through CvPlot::headUnitNode()
However, I quickly ran into some *ahem* interesting issues:
1) What if units from different domains were present. This applies to cities\forts where it is possible to have land,sea and air units stationed.
2) Some units should probably never contribute to the defender set: units in a transport (e.g. cargo), always invisible (spies), civilian units like workers, missionary (would a check against canDefend() be enough?)
3) Air units have their own stack limit so they should probably be excluded as well
4) What about invisible units like submarines that are visible to certain units classes (e.g. destroyers) ?
5) What if there were enemy units from 5 teams and the defender set limit was set at 4. We could then have a situation in which at least one team would not be represented in the defender set which would cause confusion for the AI since getBestDefender() could be called with a wide variety of parameters (i.e. "filters") and I would have to ensure that the defender set would always return a valid subset as if getBestDefender did not use the defender set. Otherwise we'd confuse the AI or create subtle bugs.
To solve this, I came up with the following:
Rule: The defender set must include one representative of any team's unit that is on the plot.
If team A,B and C have units on the same plot. The defender set must include at least one unit from these players. If A,B,C,D,E has units on the same plot, one unit is selected from each player. This is the only exception to the rule about having n defenders. It matters not which subset (or all) is at war with the player.
Without this rule it would be possible for the defender set to be composed entirely of units that the attacking player is not at war with which could confuse the AI and cause other weird bugs.
(Note that we would need other criteria like the list must also always contain at least one hostile unit that can defend)