int CvUnit:
oisonCityProb(const CvPlot* pPlot, ProbabilityTypes eProbStyle) const
{
CvCity* pCity;
CvPlot* pLoopPlot;
int iDefenseCount;
int iCounterSpyCount;
int iProb;
int iI;
//Grab pointer to city.
pCity = pPlot->getPlotCity();
//Yeah. Not much probability of poisoning a city if there ain't one there.
if (pCity == NULL)
{
return 0;
}
//isGovernmentCenter() can be found in CvCity.cpp
//This one returns true if the city is the capital, has the forbidden palace, or versailles.
//It makes it harder to poison these.
iProb = ((pCity->isGovernmentCenter()) ? 20 : 0);
//This next line gets the number of defenders in the city.
//Okay I'll describe how plotCount works:
//In this instance, it takes PUF_canDefend(which is a method), two data values(-1, -1), NO_PLAYER, and the team that owns the plot(the city owner in this case)
//It iterates through the units on the plot(the city in this case) and calls PUF_canDefend on each unit
//plotCount calls PUF_canDefend on each unit on the plot returns the total count of units where PUF_canDefend is true
//So it won't count settlers, workers, etc. but will count spearmen, tanks, etc.
//The implementation of plotCount can be found in CvPlot.cpp, PUF_canDefend is in CvGameCoreUtils but basically just calls
//canDefend() in CvUnit.cpp which is this file.
iDefenseCount = pPlot->plotCount(PUF_canDefend, -1, -1, NO_PLAYER, pPlot->getTeam());
//Get the number of counter spies on the plot
//Guess what. This works the same as above
//PUF_isCounterSpy is a method in CvGameCoreUtils.cpp that calls isCounterSpy() which is in this class. CvUnit.cpp
iCounterSpyCount = pPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());
//Okay. Got all that? Good
//Now. Our directions N, S, E, W, NE, NW, SW, SE are set in CvEnums.h If you take a look at it(search for DirectionTypes in CvEnums.h)
//you will see that NO_DIRECTION = -1, DIRECTION_NORTH = 0, DIRECTION_NORTHEAST = 1, etc... and hey!
//NUM_DIRECTION_TYPES = 8 which in fact there are 8 directions! Sneaky programmers...
//Oh yeah, The first enumeration that isn't explicitly set to a value automatically defaults to 0 and continues adding 1 to each which
//is why DIRECTION_NORTH = 0, DIRECTION_NORTHEAST = 1, and so on.
//So now we are looping through each direction 0 thru 7 which is all 8 directions
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
//((DirectionTypes)iI) on the next line is casting the loop counter int to a direction type.
//getX_INLINE() and getY_INLINE() return the plots x and y coordinate. These are both declared in CvPlot.h
//Inlines are usually declared in the .h files.
//plotDirection can be found in CvGameCoreUtils.h and is also an inline method.(inline == faster for small amounts of code)
//plotDirection basically grabs the plots in the specified direction around the current plot(the city in this case)
//This for loop we are in is iterating through the plots around the city.
//If you look at the plotDirection code you'll see that it calls more methods. I won't go into those but I'll point you in
//the right direction.
//Look at line 229 in CvGameCoreUtil.h : return GC.getMapINLINE().plotINLINE((iX + GC.getPlotDirectionX()[eDirection]), (iY + GC.getPlotDirectionY()[eDirection]));
//This returns a plot. GC.getPlotDirectionX()[eDirection] gets a number defined in CvGlobals.cpp(lines 160-182) which helps the plot go left or right one plot
//Same for the y-axis.
//CvMap.h contains some of the map inline methods used.
//You will see this kind of for loop with the directions a lot in the SDK so try to understand it.
pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));
//So now we have our plot adjacent to the city
if (pLoopPlot != NULL)
{
//The plot is there so let's add the counter spies hanging out around the city. Not just inside the city.
iCounterSpyCount += pLoopPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());
}
}
//We always take into account defenders and population. Can't make it too easy.
iProb += (iDefenseCount * 2);
//getPopulation should be self explanatory and is found in CvCity.cpp
//I divide here because I'm wanting it to be easier with higher populations(more places for the spy to hide)
iProb += 20 / (pCity->getPopulation());
//Probability types are set in CvEnums.h at line 1111(see the trend for user enum types?)
//So whatever probability we pass into our poisonCityProb method affects our probability.
//I haven't tested these numbers so I'm sure they will change when the AI poisons me to death with success every time.
switch (eProbStyle)
{
//If we want a high probability of success, well let's just not count the counter spies!
case PROBABILITY_HIGH : iCounterSpyCount = 0;
break;
//Low probability? Let's multiply the counter spy weight by 5.
case PROBABILITY_LOW : iCounterSpyCount *= 5;
break;
//Real? counter spy weight multiplied by 3
case PROBABILITY_REAL : iCounterSpyCount *= 3;
break;
//Something weird? Do nothing at all.
default :
break;
}
iProb += (50 / (iCounterSpyCount + 1));
//So in the end a capital with 10 pop, 5 spies, 5 defenders with PROBABILITY_REAL should return a 41 if my math is right.
//Prob from capital = 20
//Prob from defense = 5 * 2 = 10
//Prob from population = 20 / 10 = 2
//Prob from counter spies = 5 * 3 = 15
//20 + 10 + 2 + 15 = 47. So roughly a 53% chance which is pretty darn good so I'll most likely change these values.
return iProb;
}