Are you sure? I looked through the code that fetches the best interceptor for an air attacker, and I don't see anything that would cause fighters in a city to not be able to intercept bomber attacks against the city. Have a look for yourself if you know C++, here are the relevant bits with a few extra // comments added in for clarification (the function is called within the bomber unit's object, so calls like isEnemy() are essentially thisBomber->isEnemy() calls):
Code:
// Loop through all players' Units (that we're at war with) to see if they can intercept
for(iI = 0; iI < MAX_PLAYERS; iI++)
{
CvPlayerAI& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
// Check if the looped player is alive
if(kLoopPlayer.isAlive())
{
TeamTypes eLoopTeam = kLoopPlayer.getTeam();
// Check if the looped player's team is at war with us and this unit is not invisible to the looped player's team
if(isEnemy(eLoopTeam) && !isInvisible(eLoopTeam, false, false))
{
// Loop through all the looped player's units
for(pLoopUnit = kLoopPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kLoopPlayer.nextUnit(&iLoop))
{
// Must be able to intercept
if(pLoopUnit != NULL && !pLoopUnit->isDelayedDeath() && pLoopUnit->canAirDefend() && !pLoopUnit->isInCombat())
{
// Must not have already intercepted this turn
if(!pLoopUnit->isOutOfInterceptions())
{
// Must either be a non-air Unit, or an air Unit that hasn't moved this turn
if((pLoopUnit->getDomainType() != DOMAIN_AIR) || !(pLoopUnit->hasMoved()))
{
// Must either be a non-air Unit or an air Unit on intercept
if((pLoopUnit->getDomainType() != DOMAIN_AIR) || (pLoopUnit->GetActivityType() == ACTIVITY_INTERCEPT))
{
// Test range
if(plotDistance(pLoopUnit->getX(), pLoopUnit->getY(), interceptPlot.getX(), interceptPlot.getY()) <= pLoopUnit->getUnitInfo().GetAirInterceptRange())
{
iValue = pLoopUnit->currInterceptionProbability();
if(iValue > iBestValue)
{
iBestValue = iValue;
pBestUnit = pLoopUnit;
}
}
}
}
}
}
}
}
}
}
This function gets called by the bomber before it makes an attack, and if pBestUnit is not null (ie. an interceptor was found), the interception rolls occur the way I described them.