If you "remember attacking stacks with Pyre Zombies in the base mod, and not having it be suicide" then you might be remembering playing the version of FfH2 where Kael accidentally switched the <PythonPostCombatLost> that should have belonged to Pyre Zombies to Sons of Asena instead.
The only difference between the MNAI and base FfH2 codes here is that MNAI uses less than while FfH2 uses less than or equal to in the line that determines the random odds of creating Smoke on a forested tile.
MagisterModmod has some other minor differences, but none with the effects you describe. It has its damage capped at 99% instead of 100%, so it is not fatal. It uses the form
if not pPlot.isNone(): instead of the equivalent
if pPlot.isNone() == False: just because I think that looks nicer. It defines various variables at the top rather than redefining them during each iteration of the loop, to make things slightly more efficient.
(I am thinking that I may in future versions swap the two loops and first conditional statement with a single loop, like this:
Code:
for iDirection in range(DirectionTypes.NUM_DIRECTION_TYPES):
pPlot = plotDirection(iX, iY, DirectionTypes(iDirection))
The effects should be equivalent, but it looks nicer and I think it would be very slightly more efficient.)
I believe that def is used to introduce the definition of a function. The units are all objects, as are the plots.
pCaster refers to the unit with this <PythonPostCombatLost> effect in its xml defined, i.e., the Pyre Zombie.
pOpponent refers to the unit that it was fighting in this particular combat, the one that killed the Pyre Zombie.
iX and iY are the coordinates of the plot where the Pyre Zombie is located.
iiX and iiY are the indices of loops used to cycle through nearby tiles. Any integer variables would do here, but iiX and iiY are the ones typically used in such cases for convenience sake.
For loops cycles through lists. The range function generates a list of integers starting with the first parameter, ending just before reaching the second parameter, in increments of the third parameter.
(That is what it does if given 3 parameters. If it only has only 2 arguments, then it returns a list starting with the first of those and ending just before the last with an increment of 1. If it is given a single argument, it returns a list of numbers starting at 0 and ending just before the number it is given.)
CyMap().plot(iiX,iiY) is a function that returns the plot object with the coordinates iiX and iiY.
if not (iiX == iX and iiY == iY): is a conditional statement used to make the rest of the code not run in cases where the coordinates of the plot that the CyMap().plot(iiX,iiY) function would generate are the same as the coordinates of where the Pyre Zombie is located.
pPlot.isNone() is a boolean function that returns true if the plot does not actually exist, as when its coordinates fall outside of the bounds of the map. This is important near the edges of flat maps.
pPlot.getFeatureType() is a function which returns the feature type of the plot object. If that is a Forest, Jungle, or New Forest, then it might generate the smoke improvement that could later lead to changing the feature to Flames.
CyGame().getSorenRandNum(100, "Flames Spread") is a pseudo-random number generator that generates which is 0 or more and less than 100. "Flames Spread" is a string used to seed it.
gc.getDefineINT('FLAMES_SPREAD_CHANCE') is an integer defined in the xml.
There is an if statements whose then runs when that integer is bigger than the random one.
Under that condition it finds the improvement on the tile, and if an improvement exists checks to see if it is a permanent improvement (like Unique Features such as the Yggdrasil). It will not change a plot with a permanent improvement, but otherwise will change the improvement to Smoke.
Completely separate from any consideration of whether it will create smoke on the tile, there is a for loop which goes through all of the units on the tile.
pPlot.getNumUnits() returns the number of units on the tile, so range(pPlot.getNumUnits()) creates a list of integers starting at 0 and stopping just shy of that number.
The pPlot.getUnit(i) function uses the index of that list to identify each of the specific units on that plot.
pUnit.doDamage(10, 99, pCaster, iFire, False) damages each of those units, with a fire type damage, counted as being dealt by pCaster (the Pyre Zombie) with a base amount of damage being 10% (which can be modified by factors like the unit's relative strength and the benefits of certain promotions), not being able to damage the unit more than 99% (so it cannot be completely lethal, like it is in base FfH2 or MNAI where this number is 100), and the boolean at the end says whether this damage may cause a war.