getFacingDirection(true)

vincentz

Programmer
Joined
Feb 4, 2009
Messages
3,614
Location
Denmark
Trying to add/fix Range Attacks for Siege Weapons.
Problem is AI is not that good at it. I was looking at code and found this :

getFacingDirection(true)

Since Range Attacks are not being used in Vanilla BtS, I suspect that it is being used in the Afterworld mod. So I'm curious, does the code in fact means the unit needs to face the direction, or is it a "line of sight", and if, then why have a "pTargetPlot->isVisible" too?

cheers Vincentz

edit : a sidequestion. I want the MISSION_RANGE_ATTACK to be "pushed" to the start of AI considerations, or atleast give it top priority. Any help would be most welcome.
 
Trying to add/fix Range Attacks for Siege Weapons.
Somehow that sentence really caught my attention. Here is something I would love to know more about. Where is this code precisely? :)

Those questions are likely not that hard to answer... if you know the code, that is. I need to get there before I can even attempt to answer your questions.
 
Well, to start with the beginning : I always wanted ranged siege instead of suicide sieges.
So I changed AirDamage and AirRange for the sieges, which gives them what is known in the dll as canRangeStrike code starts here

CvUnit.cpp - > bool CvUnit::canRangeStrike() const

I added this so it couldnt shoot from cargohold in ships
Code:
	// Vincentz range if cargo off
		if (isCargo())
	{
		return false;
	}

and later in -> bool CvUnit::canRangeStrikeAt(const CvPlot* pPlot, int iX, int iY) const

I removed this, because otherwise it couldnt shoot above a forest

Code:
//	if (!pPlot->canSeePlot(pTargetPlot, getTeam(), airRange(), getFacingDirection(true)))
//	{
//		return false;
//	}



In CvGameInterface.cpp -> else if(pHeadSelectedUnit->airRange() > 0) //other ranged units

I replaced the "show where attack is possible" with the airstrike, because it would otherwise only show visible/unblocked areas. Example after fix:
Spoiler :


Code:
		else if(pHeadSelectedUnit->airRange() > 0) //other ranged units
		{
			iMaxAirRange = 0;

			pSelectedUnitNode = gDLL->getInterfaceIFace()->headSelectionListNode();

			while (pSelectedUnitNode != NULL)
			{
				pSelectedUnit = ::getUnit(pSelectedUnitNode->m_data);
				pSelectedUnitNode = gDLL->getInterfaceIFace()->nextSelectionListNode(pSelectedUnitNode);

				if (pSelectedUnit != NULL)
				{
					iMaxAirRange = std::max(iMaxAirRange, pSelectedUnit->airRange());
				}
			}

			if (iMaxAirRange > 0)
			{
				for (iDX = -(iMaxAirRange); iDX <= iMaxAirRange; iDX++)
				{
					for (iDY = -(iMaxAirRange); iDY <= iMaxAirRange; iDY++)
					{
						pLoopPlot = plotXY(pHeadSelectedUnit->getX_INLINE(), pHeadSelectedUnit->getY_INLINE(), iDX, iDY);

						if (pLoopPlot != NULL)
						{
							if (plotDistance(pHeadSelectedUnit->getX_INLINE(), pHeadSelectedUnit->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iMaxAirRange)
							{
								NiColorA color(GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_RED")).getColor());
								color.a = 0.5f;
								gDLL->getEngineIFace()->fillAreaBorderPlot(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), color, AREA_BORDER_LAYER_RANGED);
							}
						}
					}
				}
			}

		
		
		
// Vincentz off		
//			int iRange = pHeadSelectedUnit->airRange();
//			for (iDX = -(iRange); iDX <= iRange; iDX++)
//			{
//				for (iDY = -(iRange); iDY <= iRange; iDY++)
//				{
//					CvPlot* pTargetPlot = plotXY(pHeadSelectedUnit->getX_INLINE(), pHeadSelectedUnit->getY_INLINE(), iDX, iDY);
//
//					if (pTargetPlot != NULL && pTargetPlot->isVisible(pHeadSelectedUnit->getTeam(), false)) Vincentz
//					if (pTargetPlot != NULL)
//					{
//						if (plotDistance(pHeadSelectedUnit->getX_INLINE(), pHeadSelectedUnit->getY_INLINE(), pTargetPlot->getX_INLINE(), pTargetPlot->getY_INLINE()) <= iRange)
//						{
//							if (pHeadSelectedUnit->plot()->canSeePlot(pTargetPlot, pHeadSelectedUnit->getTeam(), iRange, pHeadSelectedUnit->getFacingDirection(true)))
//							{
//								NiColorA color(GC.getColorInfo((ColorTypes)GC.getInfoTypeForString("COLOR_YELLOW")).getColor());
//								color.a = 0.5f;
//								gDLL->getEngineIFace()->fillAreaBorderPlot(pTargetPlot->getX_INLINE(), pTargetPlot->getY_INLINE(), color, AREA_BORDER_LAYER_RANGED);
//							}
//						}
//					}
//				}
//			}
		}

and that, iirc, was pretty much it. In the tests I made, if I place multiple sieges, they will fire ranged attacks except for one.


to be contiued... (have a tired 3 year old son ;))

EDIT :

While the AI does use rangestrike as defense (when sieges are in city) it uses direct attack when offensive. I'd love for the AI to simply use Rangestrike before considering using direct attack ;)

Dbl EDIT :

Thinking about it, maybe its as simple as putting a :
If unit(airdamage) > 0 AND unit!=AirUnit then ->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
where the normal attack sequence is.

(I'm not a programmer and the above is of course not correct language) ;)

Maybe somewhere here :

CvUnitAI.CPP

Code:
// Returns true if a mission was pushed...
bool CvUnitAI::AI_anyAttack(int iRange, int iOddsThreshold, int iMinStack, bool bFollow)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	FAssert(canMove());

	if (AI_rangeAttack(iRange))
	{
		return true;
	}

	if (bFollow)
	{
		iSearchRange = 1;
	}
	else
	{
		iSearchRange = AI_searchRange(iRange);
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
					{
						if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) && (iPathTurns <= iRange))))
						{
							if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
							{
								iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

								if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
								{
									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
										FAssert(!atPlot(pBestPlot));
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
		return true;
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_rangeAttack(int iRange)
{
	PROFILE_FUNC();

	FAssert(canMove());

	if (!canRangeStrike())
	{
		return false;
	}

	int iSearchRange = AI_searchRange(iRange);

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;

	for (int iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (int iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
				{
					if (!atPlot(pLoopPlot) && canRangeStrikeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						int iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		getGroup()->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
		return true;
	}

	return false;
}
 
Where can I download the source code? I would like to get a better look at this, but I can't find the source code anywhere. I downloaded your mod and installed it, but it doesn't look like it contains the source code.

Another thing. Your mod is an exe. I never figured out what's wrong with a simple zip file. You know what a zip file does, but an exe can do all sorts of things and I really prefer zip files.
 
Top Bottom