Adding a tech requirenment for the Mountains: Back to Service Modcomp.

Well...

I thought I was done, but the second I released this, people were "Afforess, what about..."

Anyways, I'm adding two more modifiers for techs, affecting mountains. I already did everything in CvGameTextMgr, CvInfos, and CvTeam. The one I'm having an issue with is creating a new Boolean XML field for tech's that allows players to build cities on Peaks. It's called CanFoundOnPeaks. Well, anyways, I added some changes to CvPlayer, but I'm getting compiler errors, and I'm not sure what to change.

Here's the code:

Code:
bool CvPlayer::canFound(int iX, int iY, bool bTestVisible) const
{...


	if (pPlot->isPeak())
	{
		if (GC.getGameINLINE().isOption(GAMEOPTION_MOUNTAINS))
		{
			if ((GET_TEAM(!GC.getGameINLINE().getActiveTeam()).isCanFoundOnPeaks()))
			{
				return false;
			}
			else
			{
				return true;
			}
		}

		else
		{
			return false;
		}
	}

...
}

The errors I'm getting are


CvPlayer.cpp(6412) : error C2664: 'CvTeamAI::getTeam' : cannot convert parameter 1 from 'bool' to 'TeamTypes'
Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)
CvPlayer.cpp(6412) : error C2228: left of '.isCanFoundOnPeaks' must have class/struct/union type
 
You've got a typo with your placement of the ! operator. You are !ing the active team ID. You want this:

Code:
if (!GET_TEAM(GC.getGameINLINE().getActiveTeam()).isCanFoundOnPeaks())

I removed one level of outer parentheses because they were unnecessary. All you really need to do is move the ! to the left of GET_TEAM.
 
You've got a typo with your placement of the ! operator. You are !ing the active team ID. You want this:

Code:
if (!GET_TEAM(GC.getGameINLINE().getActiveTeam()).isCanFoundOnPeaks())
I removed one level of outer parentheses because they were unnecessary. All you really need to do is move the ! to the left of GET_TEAM.

Wow. All that for such a silly problem. At least I understood (mostly) what I was doing this time. Thanks.
 
Yes, you're making great progress. I spotted that one looking at the code, but it may help to describe the error message. It says that you are passing a bool for the first parameter to CvGame::getTeam(), but it wants a TeamTypes. We know that GC.getGameINLINE().getActiveTeam() returns a TeamTypes, so the only thing left to cause a problem was the !.
 
I had a good suggestion to expand this modcomp. I'm trying to add a promotion that allows units to move through mountains early. I'm assuming the code I need to be looking at is "CvUnit::canmoveinto()."
I already cloned everything from HillsDoubleMove in CvInfos and CvUnit and got that all set up. My problem is when I tried to add it to CvUnit::CanMoveInto(), I get errors.

Here is what I changed:
Code:
	if (pPlot->isImpassable(getTeam()))
to
Code:
	if (!(isCanMovePeaks) || (pPlot->isImpassable(getTeam())))

and it seems syntactically correct to me, but the compiler disagrees.

Here's the error:
error C2276: '!' : illegal operation on bound member function expression
 
Is isCanMovePeaks a function on CvUnit? If so, you need to add ()s to call it:

Code:
if (!(isCanMovePeaks[B][COLOR="DarkOrange"]()[/COLOR][/B]) || (pPlot->isImpassable(getTeam())))
 
Okay, I got the promotion 100% working. Now for the AI logic. At first, I was going to give it just some value so the AI would take it. But then, I realized the promotion is much more than that. If the unit can go onto a peak and hide there and heal of sneak attack a otherwise blocked off tile, it should.

I am thinking of adding this to bool CvUnitAI::AI_heal(int iDamagePercent, int iMaxPath)


Code:
	if (bRetreat)
	{
		if pPlot->isImpassable(getOwnerINLINE()) && isCanPassPeaks()
		{
			pUnitToHeal()->pushMission(MISSION_HEAL);
			return true;
		}
	}

Will that even work? Is it good?
 
This part of the code (AI) is the area with which I am least familiar, but I would think you'd need to consider nearby units that can also pass peaks (i.e. pose a danger to the healing unit). Is there code in the AI that tells it to favor forest/jungle and/or hills when deciding where to heal/move? If so, I would expect that part of the code to be a good spot to include the check for peaks.
 
This part of the code (AI) is the area with which I am least familiar, but I would think you'd need to consider nearby units that can also pass peaks (i.e. pose a danger to the healing unit). Is there code in the AI that tells it to favor forest/jungle and/or hills when deciding where to heal/move? If so, I would expect that part of the code to be a good spot to include the check for peaks.

Looks like I was looking in the wrong spot. I think "bool CvUnitAI::AI_safety()" is what I am looking for.

This line looks like the one that values defense plots.

Code:
iValue += pLoopPlot->defenseModifier(getTeam(), false);

Now, Peaks already have a +100% defense modifier (highest of any plot), so, will the unit automatically, if it can move through peaks with this promotion, consider the +100% of the peak? Or will it, because peaks are still impassible for most units, ignore it?
 
Check to make sure CvUnit::defenseModifier() doesn't ignore the modifier for peaks if the plot is impassible. If most rivals have the tech that allows peak passage, +100% should cover it. If most units still cannot pass through peaks, you should probably increase the safety value of the plot, but that's optional and a bit more fuzzy.
 
Check to make sure CvUnit::defenseModifier() doesn't ignore the modifier for peaks if the plot is impassible. If most rivals have the tech that allows peak passage, +100% should cover it. If most units still cannot pass through peaks, you should probably increase the safety value of the plot, but that's optional and a bit more fuzzy.

Nope, the code is

Code:
    if (GC.getGameINLINE().isOption(GAMEOPTION_MOUNTAINS))
    {
        if (isPeak())
        {
            iModifier += GC.getPEAK_EXTRA_DEFENSE();
        }
    }

So it should always be relevant. I guess the AI will be able to figure it out on their own, without my help.

Thanks for helping me turn this interesting modcomp into something truly awesome.
 
I have another question pertaining to this. If you recall, a while back, I added "IsCanPassPeaks()" function to CvTechInfo, which allowed for a tech to unlock movement through peaks. Well, it works great, but the AI don't value the new tech, until of course, I realized, I never exposed the new function to the AI. I made a new value for it in

Code:
 TechTypes CvPlayerAI::AI_bestTech(int iMaxPathLength, bool bIgnoreCost, bool bAsync, TechTypes eIgnoreTech, AdvisorTypes eIgnoreAdvisor) const

in CvPlayerAI.

See if you think the logic is sound:
(FYI, NUM_CITY_PLOTS_2 is the same as NUM_CITY_PLOTS in regular BTS, but got renamed because of the larger radius cities.)

Code:
								if (GC.getTechInfo((TechTypes)iI).isCanPassPeaks())
								{
									CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
									int PeaksInOurLand = 0;
									for (iI = 0; iI < NUM_CITY_PLOTS_2; iI++)
									{
										if (pLoopPlot->isPeak())
										{
											PeaksInOurLand++;
										}
									}
									
									iValue += ((PeaksInOurLand * 40) + 200);
								}


Also, can you tell me how sound some logic I added for the promotion that allows a unit to move over peaks, regardless of the tech requirement. I added comments myself, to remember what everything did.

Code:
	if (GC.getPromotionInfo(ePromotion).isCanMovePeaks()) //Afforess
	{
		CvTeam& kTeam = GET_TEAM(getTeam());
		for (iI = 0; iI < GC.getNumTechInfos(); iI++)
		{
			if (!(kTeam.isHasTech((TechTypes)iI))) //If we don't have the tech
			{
				if (GC.getTechInfo((TechTypes)iI).isCanPassPeaks()) //and the tech allows peak movements
				{
					iValue += 100; //then value this promotion alot. Otherwise, it's worthless.
				}
			}
		}
	}

Edit:

I almost forgot. The Promotion code is in

Code:
int CvUnitAI::AI_promotionValue(PromotionTypes ePromotion)
 
You are using iI (the loop tech ID) as if it were a plot index. What exactly are you hoping to do? If you want to count all peak tiles in the AI's land, loop over the whole map with a new loop counter (iJ, iK? whatever, just not something like iI that is already being used) and count the number of plots that a) are owned by the AI and b) are peaks.

Code:
int iPeakCount = 0;
for iK in total map tiles
    plot = map.plot(iK)
    if plot.isPeak() and plot.getOwnerINLINE() == getID()
        ++iPeakCount;

If you only want to count the peaks in city radii, loop over all cities owned by the AI and then loop over the plots in the city's radius, counting peaks.

Code:
int iPeakCount = 0;
for city in player cities
    for plot in city radious
        if plot.isPeak() and plot.getOwnerINLINE() == getID()
            ++iPeakCount;
 
You are using iI (the loop tech ID) as if it were a plot index. What exactly are you hoping to do? If you want to count all peak tiles in the AI's land, loop over the whole map with a new loop counter (iJ, iK? whatever, just not something like iI that is already being used) and count the number of plots that a) are owned by the AI and b) are peaks.

Oops. I forgot that iI was already being used. Yes, I want to use iJ, not iI.

My goal is to loop over all the AI's cities, then loop over all the plots that are peaks. Also, I get the feeling that looping over all the plots is a time consuming thing to do, especially when every player will do it, every time they reevaulate tech's. Is there anyway to cache the result of this, and only change it if the city count changes, or one of the cities culture expands/ decreases? Or am I worrying too much over nothing?
 
If you can figure out what Dom Pedro did in the cultural borders thread (It's still beyond me at the moment; I'll pick apart his code when he posts it), I think you can do something about adding peaks to a plotgroup when they become part of a city's cultural boundaries. Maybe keep a plotgroup that records all owned peak tiles, regardless of who owns them? Then if it's relevant, you can scan through that plotgroup and see which tiles a particular civ owns.
 
You could add a field to CvCity called m_iNumPeaks that you keep up-to-date whenever the plots that a city "controls" changes. I believe there is a function that gets called when this happens, but I'm not entirely sure.

Start by checking how CvCity::isWorkingPlot() is handled. This function checks if the city is actively working the plot, but it should take into account whether or not the city controls the plot.

If the tech evaluation function is called only once per AI per turn then it's not a big deal. If it calls it multiple times it starts to get expensive.
 
Top Bottom