Bombing Ships in Port

Joined
Jul 28, 2006
Messages
4,016
Apparently, it can't be done in any stock version of Civ 4. This is one of the few things in the game that really bug me. If you leave your battleships just outside of a city (or a fort in BtS), they are fair game, but once you pull into port, they suddenly become immune to all air strikes. A Pearl Harbor type situation is thus impossible. Besides making absolutely no sense at all, this was something Civ 2 and 3 got right, so why wasn't it carried over?

Whatever the reasons, I'll be perfectly happy so long as I can mod it in. I tried messing around earlier with XML and even increased the aircombatlimit of the planes to 100, allowing for "lethal" strikes, but it has no effect. I'm assuming that the solution lies in at least Python, and probably SDK, so how would I go about changing this? I imagine somebody has already thought about it or done something with it in another mod.
 
Ok, in the SDK its a bit complicated but here goes...

The problem is that any unit with DOMAIN_SEA can't defend unless it's in a water plot and all cities are land plots. In CvPlot.cpp we have the CvPlot::isValidDomainForAction() which will return false for ships in anything but water plots. That's called by CvUnit::canDefend() for most combat actions in CvUnit.cpp, and so on... :)

What is probably the easiest 'hack' to get it to work in the SDK is to create an exception for air strikes. In CvUnit.cpp you have CvUnit::airStrikeTarget() which calls canDefend() and CvUnit::airStrike() which calls both canDefend() and airStrikeTarget(). And finally you have CvUnit::collateralCombat() which also calls canDefend() before applying collateral damage. You'll need to modify all three of those method in CvUnit (airStrikeTarget, airStrike and collateralCombat) to make an exception for naval units. You'll also need to be careful to in collateralCombat() or you'll make naval units vulnerable to all types of collateral damage, not just air strikes.

So... here's what I have so far, but it needs to more testing:
Spoiler :
Code:
bool CvUnit::airStrike(CvPlot* pPlot)
{
	if (!canAirStrike(pPlot))
	{
		return false;
	}

	if (interceptTest(pPlot))
	{
		return false;
	}

	CvUnit* pDefender = airStrikeTarget(pPlot);

	FAssert(pDefender != NULL);
/*** World Piece Begin ***/
	if ( !(pDefender->getDomainType() == DOMAIN_SEA && !(pPlot->isWater())) )
	{ // Exception for naval units in cities
		FAssert(pDefender->canDefend());
	}
/*** World Piece End ***/

	setReconPlot(pPlot);

	setMadeAttack(true);
	changeMoves(GC.getMOVE_DENOMINATOR());

	int iDamage = airCombatDamage(pDefender);

	int iUnitDamage = std::max(pDefender->getDamage(), std::min((pDefender->getDamage() + iDamage), airCombatLimit()));

	CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ARE_ATTACKED_BY_AIR", pDefender->getNameKey(), getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_AIR_ATTACK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

	szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ATTACK_BY_AIR", getNameKey(), pDefender->getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_AIR_ATTACKED", MESSAGE_TYPE_INFO, pDefender->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

	collateralCombat(pPlot, pDefender);

	pDefender->setDamage(iUnitDamage, getOwnerINLINE());

	return true;
}

Code:
CvUnit* CvUnit::airStrikeTarget(const CvPlot* pPlot) const
{
	CvUnit* pDefender;

	pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

	if (pDefender != NULL)
	{
		if (!pDefender->isDead())
		{
/*** World Piece Begin ***/
			if (pDefender->canDefend() || (pDefender->getDomainType() == DOMAIN_SEA && !(pPlot->isWater())))
			{
				return pDefender;
			}
/*** World Piece End ***/
		}
	}

	return NULL;
}

Code:
void CvUnit::collateralCombat(const CvPlot* pPlot, CvUnit* pSkipUnit)
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	CvWString szBuffer;
	int iCollateralStrength;
	int iTheirStrength;
	int iStrengthFactor;
	int iCollateralDamage;
	int iUnitDamage;
	int iDamageCount;
	int iPossibleTargets;
	int iCount;
	int iValue;
	int iBestValue;
	std::map<CvUnit*, int> mapUnitDamage;
	std::map<CvUnit*, int>::iterator it;

	iCollateralStrength = ((((getDomainType() == DOMAIN_AIR) ? airBaseCombatStr() : baseCombatStr()) * collateralDamage()) / 100);

	if (iCollateralStrength == 0)
	{
		return;
	}

	iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit != pSkipUnit)
		{
			if (isEnemy(pLoopUnit->getTeam(), pPlot))
			{
				if (!(pLoopUnit->isInvisible(getTeam(), false)))
				{
/*** World Piece Begin ***/
					if (pLoopUnit->canDefend() || (getDomainType() == DOMAIN_AIR && pLoopUnit->getDomainType() == DOMAIN_SEA && !(pPlot->isWater())))
					{ // Exception for naval units in cities when attacked by air units
						iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "Collateral Damage"));

						iValue *= pLoopUnit->currHitPoints();

						mapUnitDamage[pLoopUnit] = iValue;
					}
/*** World Piece End ***/
				}
			}
		}
	}

	iDamageCount = 0;
	iCount = 0;

	while (iCount < iPossibleTargets)
	{
		iBestValue = 0;
		pBestUnit = NULL;

		for (it = mapUnitDamage.begin(); it != mapUnitDamage.end(); it++)
		{
			if (it->second > iBestValue)
			{
				iBestValue = it->second;
				pBestUnit = it->first;
			}
		}

		if (pBestUnit != NULL)
		{
			mapUnitDamage.erase(pBestUnit);

			if (NO_UNITCOMBAT == getUnitCombatType() || !pBestUnit->getUnitInfo().getUnitCombatCollateralImmune(getUnitCombatType()))
			{
				iTheirStrength = pBestUnit->baseCombatStr();

				iStrengthFactor = ((iCollateralStrength + iTheirStrength + 1) / 2);

				iCollateralDamage = (GC.getDefineINT("COLLATERAL_COMBAT_DAMAGE") * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor);

				iCollateralDamage -= (iCollateralDamage * pBestUnit->getCollateralDamageProtection()) / 100;

				iCollateralDamage = std::max(0, iCollateralDamage);

				int iMaxDamage = std::min(collateralDamageLimit(), (collateralDamageLimit() * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor));
				iUnitDamage = std::max(pBestUnit->getDamage(), std::min(pBestUnit->getDamage() + iCollateralDamage, iMaxDamage));

				if (pBestUnit->getDamage() != iUnitDamage)
				{
					pBestUnit->setDamage(iUnitDamage, getOwnerINLINE());
					iDamageCount++;
				}
			}

			iCount++;
		}
		else
		{
			break;
		}
	}

	if (iDamageCount > 0)
	{
		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SUFFER_COL_DMG", iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(pSkipUnit->getOwnerINLINE(), (pSkipUnit->getDomainType() != DOMAIN_AIR), GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE(), true, true);

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_INFLICT_COL_DMG", getNameKey(), iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE());
	}
}

Hope that helps.
 
Road to War has a port bombing mission for bombers.

I'm working on separating out the bombing missions into their own mod component. So keep your eye on that forum in the next few days. :)

Edit: BTW, the port bombing mission does damage to ships in port with a chance to sink them. I assume that's the type of thing you're looking for?
 
Sweet!!!!!!
 
Bellissimo! I will include it in the next version of WWII in the Pacific, once I get my SDK up and running (along with Ranged Bombardment, of course). Now I don't have to bug Dale about airbombing buildings, either. :goodjob:
 
Top Bottom