Zoc

I didn't know there existed something like "p2Plot.getVisibleEnemyUnits () > 0". Did you create that yourself?

But anyway, I'd prefer your method for human-only games. However I fear the AI can't be trusted to use your method to its full effect. Therfore I tried to make my method dummy-proof.

The AI can't be trusted to man all their forts. So it's better for their mere existence to be sufficient trigger. Also the AI likes to pillage everything in enemy territory. With your method they would be penalized for this; with my method rewarded.
 
make the fort give -30% defense to enemies in all surrounding tiles/cleared land terrain feature, as well a +50% withdrawl bonus
or have it create -30% defence in the tiles near it(excluding forts)
 
M@ni@c said:
I didn't know there existed something like "p2Plot.getVisibleEnemyUnits () > 0". Did you create that yourself?

No, I didn't write it myself. There's several functions you could call on a plot that would seem to be useful for detecting enemies there.
# CvPlot::isVisibleEnemyDefender
# CvPlot::*getVisibleEnemyDefender
# CvPlot::getNumDefenders
# CvPlot::getNumVisibleEnemyDefenders
# CvPlot::getNumVisiblePotentialEnemyDefenders

The AI can't be trusted to man all their forts. So it's better for their mere existence to be sufficient trigger. Also the AI likes to pillage everything in enemy territory. With your method they would be penalized for this; with my method rewarded.

Ah...I am working on a fix for the AI manning forts.
I can get the AI to man forts in their territory perhaps 90% of the time now.
With some of the changes I've made it is even common to see more than one unit in a fort for a little while.

One key change is to make the AI build more RESERVE units. You can do that with an XML change in the leaderheads. RESERVE units get missions like protect, defend, and guard bonus, which are the types of missions that would get you to stand around in a fort...since there is no garrison fort mission.

I'm fairly satisfied with what I've been able to do in terms of getting the AI to man the forts.

A bigger problem is getting the AI to deal with player forts.

In my code, units are halted and they take a little damage per enemy unit in a fort. Well, the AI just sends hoards of units to their doom. If I man a fort with 10 STR 10 units, it can be enough to kill lesser units...but the AI happily runs right up to the fort, and certain doom, because it doesn't understand ZOC.

It's somewhat awkward to get the AI to deal with this. I'm attempting to deal with it on a mission by mission basis. If I can get the AI to run around ZOC when appropriate, I'll post the code.
 
bdmarti said:
A bigger problem is getting the AI to deal with player forts.

In my code, units are halted and they take a little damage per enemy unit in a fort. Well, the AI just sends hoards of units to their doom. If I man a fort with 10 STR 10 units, it can be enough to kill lesser units...but the AI happily runs right up to the fort, and certain doom, because it doesn't understand ZOC.

It's somewhat awkward to get the AI to deal with this. I'm attempting to deal with it on a mission by mission basis. If I can get the AI to run around ZOC when appropriate, I'll post the code.

you could try fooling the ai into thinking that those areas had a slightly lower defense?, and give mounted units immunity to zoc as they can escape easily....(don't recieve defensive boni, allowing the ai to percive that as well)
 
That is exactly what I was going to say.... throw in a negative defensive bonus (might need to make it heavy for the AI to "prefer" an alternative route)... and see if the AI re-routes around the fort.
 
Oldfrt said:
That is exactly what I was going to say.... throw in a negative defensive bonus (might need to make it heavy for the AI to "prefer" an alternative route)... and see if the AI re-routes around the fort.

I'd love to make the AI prefer another route. The problem is, I can't find the path making code.

Here's what seems to happen:
The AI calls the GeneratePath method for a bunch of plots, and then depending on it's mission it chooses the best destination plot within the mission code.
Once it has the best destination plot, it asks the generated path for that destination to give it the EndOfTurnPlot, so that it can move it's unit to that plot and make progress toward it's eventual destination.

I can't find the GeneratePath code at all.
The closest I can get is this line:
gDLL->getFAStarIFace()->GeneratePath(&GC.getPathFinder()...
But I don't seem to have the FAStarIFace class and the GC.getPathFinder only returns "m_pathFinder" and as far as I can see "m_pathfinder is never even set, so I have no idea how it does what it does.

The only thing I seem to be able to do is "second guess" the path finder code by examining the "EndOfTurn" plot it suggests and then suggest a different "EndOfTurn" plot based upon ZOC or whatever I like.

It's really annoying though because one needs to edit each and every mission to account for this type of thing.

If someone can find the path generation code, that would probably be a better way to handle things.

I must admit, I think that giving calvalry immunity to damage from forts would be a good bonus for calvalry. I'd still like to halt their movement though.
Perhaps I'll make units that have "cover" or the anti-siege promotion also be immune to damage.
Then, I can use the existance of enemy forts to encourage the AI to build more calvalry and promote more often with the "counter" promotions to forts.
In that way, I may not need to worry about the pathing as much.

but if anyone does know where the pathing code is could you tell me?
 
bdmarti said:
but if anyone does know where the pathing code is could you tell me?

It's probably in the main executable, like the graphical engine, the python interpreter and that annoying 18-civs limitation are. You only have access to a DLL, not the whole program.
 
I'm pleased with the results I am getting from the AI in terms of building and using forts reasonably well. I hope to post my code soon and it would be great if others would agree to test it out...it'd be really great if someone on the desing team would test it out as I hope the types of changes I've made can be integrated into the official mod.

Here's a summary of what I've done:
Changed the SDK AI_Heal, AI_GuardBonus, AI_DefendPlot and AI_RetreatToCity methods. These methods now take into account the presence of a fort. Units next to controlled forts that need to heal will go there and units closer to a controlled fort than to a city will go there to retreat.
Units given a "defend" mission will choose to defend forts if there is no city or unit in need of help.
The GuardBonus method now likes to guard Tower bonuses much like they like to guard mana bonuses.

Changed the XML to give Tower Bonuses a 100% chance to appear when a fort is a worked tile.
Changed the XML to give Forts a small negative yeild that is increased via different Civics, Techs, and situations. With the right civics and techs, the AI will build forts on hills, particularly next to rivers on forrested hills. I have yet to see fort spam.
Changed the XML to allow forts only on hills but not to chop forrest.
Changed the XML to give forts + 50% defense.
Changed the XML to make forts take longer to build and yeild more to pillaging, as I have yet to stop the AI from pillaging my forts.

Edited the onUnitMove python method to stop units that enter a fort ZOC and then to inflict some damage to non-monuted, units that don't have the cover promotion based upon the STR of each unit in the fort as if it were defending.

What all this means:
Forts will have at least a defensive value of +90% because they are on hills and they can gain even more from forrests.
Forts will have a yeild similar to Windmills with either the Aristocracy or Conquest civics, and they will have yeilds better than windmills on forrested plots, river plots, or if the player also has the Military Disipline or Military State Civics. This results in AI players that prefer one or more of these civics building forts on the appropriate tiles.
However, this also results in forts being TOO powerful for a human player that can and will use all the civic buffs to maximize forts output.

What's left?
Encourage the AI to NOT pillage forts in enemy territory that it can instead stand in?
Add more promotions or units that don't take damage from forts?
Tweak the yeilds of forts.

Under a financial leader, next to a river, on a forrested grassland hill on a road, with all the proper civics a fort will have a yield of 3F/2P/5C

Or on a similar plains hill it would have 2F/3P/5C

Which is great as far as getting the AI to build them, but pretty uber as far as improvements go.
One way to temper the situation might be to raise the cost of the civics themselves.
There are also windows of opportunity that the AI will use to build forts provided it has the right civics but doesn't know how to build windmills.
A problem I've had some trouble overcomming is getting the AI to build a fort with just 1 or 2 of the appropriate techs/civics but not needing to blow the value of forts up in proportion to the windmill which is it's primary competitor.

One other way to get the AI to prefer Forts might be to tweak the LeaderInfo improvment favorites such that they will sometimes disproportionatly value forts, perhaps even randomly.
 
I've decided to ignore the pathing issues that the AI has when it comes to forts and ZOC and instead have the AI count the number of enemy forts there are when it is choosing what promotion to get or what unit to build and use that value to increase the chance of building or promoting in an anti-fort manner.

This, in conjunction with a lowering of the damage done by forts has resulted in the AI producing and sending forth some decent anti-fort armies in my testing.

so it's behavior against forts isn't too bad...IMO...
 
I was going to release my FORT code today...but then I re-wrote it over the weekend.

I got rid of all references to IMPROVEMENT_FORT in my SDK changes and changed my detection technique to getDefensiveModifier() > 0 such that any number of arbitrary defensive fortifications could be detected and used by the AI.

I also made the AI weight decisions based upon the size of the defensive modifieer.

I've solved the problem of needing to give FORTs and other defensive improvements a yeild by adding a few lines to the AI improvement building methods. The AI will now take into account defensive modifiers when choosing how to improve a square.
My initial function gives a yeild something like this:
25 + 2/5 * defensiveModifier + (number of players at war with) - (number of other non-yeilding improvements of this type in the city squared)

For a fort with a +50% defensive modifier would start with a +45 yield to the AI, which makes it more attractive to the AI than a single food in most cases.
I haven't tested this yet, but I think the AI will build forts on forrested hills now provided either commerce or food is emphasised but the city isn't starving. Non-forrested hills will usually get windmills or mines, and a city isn't likely to build more than 1 fort unless it is at war or it's leader is givern a preference for them.
 
Below is a simple ZOC function for python.
It stops enemy units that move into a square adjecent to an occupied fort and then it gives each unit in the fort one attack against the moving unit.
Mounted units and units that are invisible or have the cover promotions are not damaged.

To use this code yourself, create a python file named ffhFort.py and put it with the other python files for ffh.
Then just add the following line to the def onUnitMove(self, argsList) in the CvEventManager.py file:

ffhFort.zoc(pPlot, pUnit, pPlayer)



Code:
#
#
#

from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import CvWBPopups
import PyHelpers
import Popup as PyPopup
import CvCameraControls
import CvTopCivs
import sys

gc = CyGlobalContext()


# class ffhZoc:
def zoc(pPlot, pUnit, pPlayer):
    szIcon = "Art/Interface/Buttons/Actions/fortify.dds"
          
    iDamage = 0		
    iX = pPlot.getX()
    iY = pPlot.getY()
    
    # Check each plot surrounding the current plot for enemy forts
    for iiX in range(iX-1, iX+2, 1):
        for iiY in range(iY-1, iY+2, 1):
            pCurrentPlot = CyMap().plot(iiX,iiY)
            if (pCurrentPlot.getImprovementType() == gc.getInfoTypeForString("IMPROVEMENT_FORT") and pCurrentPlot.getNumVisibleEnemyDefenders(pPlayer.getID()) > 0):
                # Stop the unit 
                if (pUnit.canMove() or pUnit.getMoves() != 0): #Should only happen once per unit
                    pUnit.finishMoves()
                    CyInterface().addMessage(pUnit.getOwner(),True,25,pUnit.getName() + " had it's movement halted by a fort.",'AS2D_DISCOVERBONUS',1,szIcon,ColorTypes(8),pUnit.getX(),pUnit.getY(),True,True)
                # If the moving unit is mounted or has the appropriate counter promotions, stop here
                if (pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_INVISIBLE')) or
                    pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_COVER')) or
                    pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_COVER2')) or
                    pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED')                  ) :
                    return;
                # For each unit in an enemy fort, attack the moving unit once as if it were attacking the fort		
                for iUnit in range(pCurrentPlot.getNumUnits()):
                    pFortUnit = pCurrentPlot.getUnit(iUnit)
                    iOdds = (1000-getCombatOdds(pUnit, pFortUnit)) # Fort Defender's odds
                    # print "iOdds=",iOdds
                    # print "STR=",pFortUnit.currCombatStr(pPlot, pFortUnit)
                    iDamage += (iOdds*pFortUnit.currCombatStr(pPlot, pFortUnit)/100000)*CyGame().getSorenRandNum(100, "Fort")/100 or 1
                    if (pFortUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') or pFortUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_SIEGE')) :
                        iDamage += 1 # archers and siege do extra damage...
    if (iDamage > 0):	
        if (iDamage > 99): # cap damage at 99
            iDamage = 99
        # print "iDamage=",iDamage
        pUnit.NotifyEntity(gc.getInfoTypeForString("MISSION_DAMAGE"))
        pUnit.setDamage(iDamage, True)
        message1 = "%s hit for " %(pUnit.getName()) 
        message2 = "%d damage." %(iDamage)
        strMessage = message1 + message2
        CyInterface().addMessage(pUnit.getOwner(),True,25,strMessage,'AS2D_DISCOVERBONUS',1,szIcon,ColorTypes(8),pUnit.getX(),pUnit.getY(),True,True)
        CyInterface().addMessage(pCurrentPlot.getOwner(),True,25,strMessage,'AS2D_DISCOVERBONUS',1,szIcon,ColorTypes(8),pUnit.getX(),pUnit.getY(),True,True)
# TODO notify player what happens in forts that are occupied in enemy lands
 
Below is some code that I'm testing to get the AI to build forts and other defensive improvements by taking into account the defensive value of improvements in the CvCityAI::AI_bestPlotBuild method.

I hope others here, especially members of the design team here, will examine this code, offer suggestions, and maybe even try it out.

Code:
// FFH begin bdmarti changes 11/3/2006 -- we need ivalue to be greater than one
				iValue += GC.getImprovementInfo(eFinalImprovement).getDefensiveModifier() / 2;
				// FFH end bdmarti changes
                
				if (iValue > 0) {
					for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++) {
						/*FfH: Modified by Chalid AIImprovements*/
						//						aiFinalYields[iJ] = (pPlot->calculateNatureYield(((YieldTypes)iJ), getTeam(), bIgnoreFeature) + pPlot->calculateImprovementYieldChange(eFinalImprovement, ((YieldTypes)iJ), getOwnerINLINE(), true));
						aiFinalYields[iJ] = (pPlot->calculateNatureYield(((YieldTypes)iJ), getTeam(), bIgnoreFeature) + pPlot->calculateImprovementYieldChange(eFinalImprovement, ((YieldTypes)iJ), getOwnerINLINE(), false));
						//FfH: End Modify
					}

					iValue += (aiFinalYields[YIELD_FOOD] * (((bEmphasizeFood) ? 26 : 19) + ((bLowFood) ? 8 : 0) + ((bNeedFood) ? 14 : 0)));
					iValue += (aiFinalYields[YIELD_PRODUCTION] * ((bEmphasizeProduction) ? 35 : 15));
					iValue += (aiFinalYields[YIELD_COMMERCE] * ((bEmphasizeCommerce) ? 8 : 7));

					iValue += (min(0, (aiFinalYields[YIELD_FOOD] - GC.getFOOD_CONSUMPTION_PER_POPULATION())) * ((bLowFood) ? 21 : 12));

					// FFH begin bdmarti changes 11/3/2006
                    // take into account the defensive value of improvements
                    if (GC.getImprovementInfo(eFinalImprovement).getDefenseModifier() > 0)
                    {
					    // Use DefensiveModifier instead of just ImprovementType to account for other future improvements
					    iValue += GC.getImprovementInfo(eFinalImprovement).getDefenseModifier() * 2 / 5;
					    /* This multiplier results in an iValue of 45+ for +50% forts which is better than 1 food provided by windmills in all but the worst cases
					    Mines will be built for all mine appropriate bonuses,
					    Mines will be built if production is emphasized,
					    Windmills will be built if food is emphasized and needed,
					    Forts will be built if Food is emphasized but not needed, or if commerce is emphasized.
			  
					    */ 
                        // Increase chances of building defensive improvements while at war
                        for (iI = 0; iI < MAX_PLAYERS; iI++)
	                    {
		                    if (GET_PLAYER((PlayerTypes)iI).isAlive())
		                    {
			                    if (atWar(GET_PLAYER((PlayerTypes)iI).getTeam(), getTeam()))
			                    {
                                    iValue++;  
			                    }
		                    }
	                    }
                        // Decrease inclination to build defensive improvements with NO yeild improvement,like forts, after a city has a few...  
                        if((pPlot->calculateImprovementYieldChange(eFinalImprovement, ((YieldTypes)0), getOwnerINLINE(), false) +
                            pPlot->calculateImprovementYieldChange(eFinalImprovement, ((YieldTypes)1), getOwnerINLINE(), false) +
                            pPlot->calculateImprovementYieldChange(eFinalImprovement, ((YieldTypes)2), getOwnerINLINE(), false) )
                         == 0 )
                        {   
                            iCount = 0;                            
                            for (iI = 0; iI < NUM_CITY_PLOTS; iI++) {
			                    if(getCityIndexPlot(iI)->getImprovementType() == eFinalImprovement) 
                                {
                                    iCount++;
                                }
		                    }
                            iValue -= iCount*iCount;  // exponentially decrease a city preference for no yield defensive improvements
                        }
                    }                        
					// FFH end bdmarti changes

Edit to fix known bugs and typos. Use at your own risk...
 
Have forts "produce" the Tower Bonus at 100% rate via XML and add the following code to CvPlayerAI::AI_bonusVal(BonusTypes eBonus)

Code:
//FfH: End Add
// ffh: bdmarti changes begin 11/3/2006
	if (eBonus==(BonusTypes)GC.getInfoTypeForString("BONUS_TOWER"))
         {
             iValue += 300;
         }
// ffh: bdmarti changes end

This puts the tower bonus about on par with other mana types as far as the AI wanting to guard them.

Next...encourage patroling units to hover around forts with this code in the
CvUnitAI::AI_patrol() method:

Code:
							if (pAdjacentPlot->isRevealedGoody(getTeam()))
							{
								iValue += 100000;
							}

							if (pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE())
							{
								iValue += 10000;
							}
							// FFH Begin bdmarti changes 11/3/2006
							// If a unit is looking for a direction  then defensive improvements are a good choice...
							if (GC.getImprovementInfo(pAdjacentPlot->getImprovementType()).getDefenseModifier() > 0) 
							{
								iValue += 1000 * GC.getImprovementInfo(pAdjacentPlot->getImprovementType()).getDefenseModifier();
							}
							// end bdmarti changes
						}

then...encourage retreating units to go to forts if they are next to them, rather than run to a city with this code in CvUnitAI::AI_retreatToCity(bool bPrimary, bool bAirlift, int iMaxPath):
Code:
	// ffH: bdmarti changes start 10/20/2006
	// If we are next to a friendly defensive improvement and this is closer than the city move there
	if(iBestValue > 1) {
		CvPlot* pAdjacentPlot;
		int iI;
		for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
		{
			pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
			if (pAdjacentPlot != NULL)
			{  // if a unit is next to a defensive improvement like a fort, can fight, and will not encounter the enemy, and this is closer than the city, then move to the fort rather than the city
                // A defensive threshold other than > 0 might be nice to add to the XML and use here
				if (GC.getImprovementInfo(pAdjacentPlot->getImprovementType()).getDefenseModifier() > 0 && getGroup()->canFight() && !pAdjacentPlot->isVisibleEnemyUnit(getOwnerINLINE())) 
				{
					pBestPlot = pAdjacentPlot;
				}
			}
		}	
	}
	//bdmarti changes end

finally, change CvUnitAI::AI_defendPlot(CvPlot* pPlot) to encourage units to defend plots with defensive improvements when they are looking for a defend mission:
Code:
	else
	{
		if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= ((atPlot(pPlot)) ? 1 : 0))
		{
			if (pPlot->plotCount(PUF_cannotDefend, -1, -1, getOwnerINLINE()) > 0)
			{
				return true;
			}
		}
        // ffh Begin bdmarti changes 11/3/2006
		// If a unit is looking for a defend mission then defensive improvements, like forts, are a good choice...
		if (GC.getImprovementInfo(pPlot->getImprovementType()).getDefensiveModifier() > 0) 
		{
			return true;
		}
		// end bdmarti changes
	}

one problem with this last bit of code is that a unit might choose to defend a fort instead of a wandering worker or settler...but I'm sure we can fix that.

Edit: fixed known typos. use this code at your own risk...
 
Wow, bdmarti! This all looks very promicing at making the fort a more viable option, but for those a bit slower (like myself), could you summarize the net effects that this achieves (X healing bonus, x defense bonus, build where, without removing forest, AI effects, other things - sight bonus, withdraw bonus, etc...)?
 
PapaMonkey said:
Wow, bdmarti! This all looks very promicing at making the fort a more viable option, but for those a bit slower (like myself), could you summarize the net effects that this achieves (X healing bonus, x defense bonus, build where, without removing forest, AI effects, other things - sight bonus, withdraw bonus, etc...)?

The code above doesn't change the defense bonus, or change where and how you can build forts. You need to make XML changes for that.

The Python ZOC code has an explanation with it and the SDK code is changing the AI behavior.
To summarize what the SDK changes do:

1. Sentry Tower bonuses will be guarded by the AI at about the same freqency as Mana bonuses. Thus, if the AI has some RESERVE units looking for a mission, there is a fair chance that they will go fortify in a fort.
This change reuires 2 XML changes to be effective: A) forts must be the resource that "harvests" sentry tower bonuses, and B) Forts should randomly produce sentry towers 100% of the time

2. The AI will move to a fort to heal if it is next to a fort and the enemy does not ocupy that fort.

3. The AI will tend to like to patrol around forts. So if Units are on Patrol, they will walk around forts more often...and this helps feed #2

4. The AI will take into account defensive bonuses (of improvements) when trying to decide what Improvement to build on a plot. I've tried to start the value of a +50% defensive bonus at about that of a windmill as far as the AI is concerned. Then I gave this a little boost if the AI is at war, and to avoid spamming of a particular defensive bonus, I count the number of other improvements of that type in a city radius and decrease the odds of the AI building more than 1 or 2 of them.

With these changes, and a few tweaks to the XML different leaders and different civics could result in many to no forts being produced.

In particular, a change in the XML to promote more RESERVE units results in more bonus plots being guarded, and in conjunction with the tower bonus always appearing in forts, the AI loves to guard them.

I haven't seen much harm in pushing up the RESERVE units by a factor of 5 to 10. RESEERVE units are nice in that they can have a lot of different missions from guarding cities to joining attack groups...and they are the only AI type that guards bonus plots which is important.

These changes will not stop the AI from pillaging a fort in enemy territory, even when it might be smarter to do so. I'm looking at the pillaging code to try to figure out a good way for the AI to occupy an enemy fort rather than tear it down all the time.
 
It looks like getting AI units to fortify in defensive improvements within enemy territory is about a 3 line fix in the AI_pillage method. The question is, is this a desireable behavior?

Would we want units that can use the bonus of a defensive improvement to fortify there rather than rip it down? Or would that be too much of a fly-trap for enemy AI units?

I don't know how often the AI will reset mission priorities and if you put enough forts around a city, how effectivly would the AI still attack your city?
 
I agree - pillage is better in terms of not having to worry about what the AI is going to do with them..
 
how hard would it be to have the consider distance from city into where it builds forts? typically as a player i tend to not want forts withing 1 square of any city and actually prefer to have them in the 3rd ring around my city spaced with 2 empty squares between them.
 
daladinn said:
how hard would it be to have the consider distance from city into where it builds forts? typically as a player i tend to not want forts withing 1 square of any city and actually prefer to have them in the 3rd ring around my city spaced with 2 empty squares between them.

It wouldn't be too hard...The following methods will find a city and tell you how far you are from a given plot. Using these methods it wouldn't be difficult at all to make the AI prefer plots 2 or 3 plots from a city for forts. Perhaps I'll try to come up with something.


pNearestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getID(), NO_TEAM, !(pLoopPlot->isWater()));

plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pCity->getX_INLINE(), pCity->getY_INLINE())
 
Back
Top Bottom