Having Trouble Allowing Para drops from Airbase (SDK)

Padjur

Prince
Joined
Nov 16, 2009
Messages
318
Having got the hang of the XML part of modding, I'm now trying to break into the SDK and could do with some help :crazyeye:

What I want to do in my mod is to remove Air units and Sea units ability to base in forts but keep the fort's, control of resource's ability (the bActAsCity tag).
Instead make an Airbase improvement for Air Units to base on and also make it so that Paradrops can be made from airbases as well as friendly cities.
I created an Airbase and a bAirbase XML tag for the ImprovementInfos.xml, did the schema and did the sdk bAirbase entries in CVinfos.cpp and h and that compressess ok.

Now the problem is to find out how to use it to allow air units to base on the new improvement and paradrops to be made.

In CvUnit, in the function "CvUnit::canParadrop" there's this code
Code:
 if (!pPlot->isFriendlyCity(*this, true))
{
return false;
}
So I've tried adding lots of code to it to say-if not isAirbase return false-as well. Like....
Code:
 if (GC.getImprovementInfo(eImprovement).isAirbase())
	{
		if (!isAirbase())
        {
            return false;
        }
	}
}
doesn't work, it throws up these errors.
'eImprovement' : undeclared identifier|
left of '.isAirbase' must have class/struct/union type|
'isAirbase': identifier not found, even with argument-dependent lookup|
So I guess I'm missing something somewhere but I don't know what.
I put code in cvPlot.cpp (trying to follow examples in Chinese American's More Trade Routes modpack) to reference it like below, with no success, so any ideas anyone?

Like I say I'm fumbling in the dark here so any light on the problem would be cool. Thanks
This is the code in cvPlot.cpp for isActsAsCity and isFriendlyCity
Code:
bool CvPlot::isCity(bool bCheckImprovement, TeamTypes eForTeam) const
{
	if (bCheckImprovement && NO_IMPROVEMENT != getImprovementType())
	{
		if (GC.getImprovementInfo(getImprovementType()).isActsAsCity())
		{
			if (NO_TEAM == eForTeam || (NO_TEAM == getTeam() && GC.getImprovementInfo(getImprovementType()).isOutsideBorders()) || GET_TEAM(eForTeam).isFriendlyTerritory(getTeam()))
			{
				return true;
			}
		}
	}

	return (getPlotCity() != NULL);
}


bool CvPlot::isFriendlyCity(const CvUnit& kUnit, bool bCheckImprovement) const
{
	if (!isCity(bCheckImprovement, kUnit.getTeam()))
	{
		return false;
	}

	if (isVisibleEnemyUnit(&kUnit))
	{
		return false;
	}

	TeamTypes ePlotTeam = getTeam();

	if (NO_TEAM != ePlotTeam)
	{
		if (kUnit.isEnemy(ePlotTeam))
		{
			return false;
		}

		TeamTypes eTeam = GET_PLAYER(kUnit.getCombatOwner(ePlotTeam, this)).getTeam();

		if (eTeam == ePlotTeam)
		{
			return true;
		}

		if (GET_TEAM(eTeam).isOpenBorders(ePlotTeam))
		{
			return true;
		}

		if (GET_TEAM(ePlotTeam).isVassal(eTeam))
		{
			return true;
		}
	}

	return false;
}
 
You have one simple error and one thing I don't understand. The simple error is to replace "eImprovement" with "getImprovementType()" so it uses the plot's improvement type. You can see an example of this on the first line of isCity() that you posted. The part I don't understand is that you first check if the improvement is an airbase, and then you ask the plot if it's an airbase (line 3 of your 2nd code block). Did you write a new function CvPlot::isAirbase?

If not, I recommend that you do. It should work like isCity(): it will say whether or not units can treat the plot can as an airbase, and it should probably take a similar set of parameters. My guess is that you want this to be true if

  1. the plot is a friendly real city without any visible enemy units in it, or
  2. the plot is a friendly airbase improvement without any visible enemy units in it.
Here are complementary functions to is[Friendly]City(): isAirbase() and isFriendlyAirbase():

Code:
bool CvPlot::isAirbase(bool bCheckImprovement, TeamTypes eForTeam) const
{
	if (bCheckImprovement && NO_IMPROVEMENT != getImprovementType())
	{
		if (GC.getImprovementInfo(getImprovementType()).isAirbase())
		{
			if (NO_TEAM == eForTeam || (NO_TEAM == getTeam() && GC.getImprovementInfo(getImprovementType()).isOutsideBorders()) || GET_TEAM(eForTeam).isFriendlyTerritory(getTeam()))
			{
				return true;
			}
		}
	}

	// assumes cities are still usable as air bases
	// if not, chnage next line to "return false;"
	return (getPlotCity() != NULL);
}

bool CvPlot::isFriendlyAirbase(const CvUnit& kUnit, bool bCheckImprovement) const
{
	if (!isAirbase(bCheckImprovement, kUnit.getTeam()))
	{
		return false;
	}

	if (isVisibleEnemyUnit(&kUnit))
	{
		return false;
	}

	TeamTypes ePlotTeam = getTeam();

	if (NO_TEAM != ePlotTeam)
	{
		if (kUnit.isEnemy(ePlotTeam))
		{
			return false;
		}

		TeamTypes eTeam = GET_PLAYER(kUnit.getCombatOwner(ePlotTeam, this)).getTeam();

		if (eTeam == ePlotTeam)
		{
			return true;
		}

		if (GET_TEAM(eTeam).isOpenBorders(ePlotTeam))
		{
			return true;
		}

		if (GET_TEAM(ePlotTeam).isVassal(eTeam))
		{
			return true;
		}
	}

	// assumes airbase improvements in neutral land are invalid
	return false;
}

Don't forget to add the declarations for the above functions to CvPlot.h as well.

Code:
bool isAirbase(bool bCheckImprovement, TeamTypes eForTeam) const;
bool isFriendlyAirbase(const CvUnit& kUnit, bool bCheckImprovement) const;

Finally, change the original canParadrop() slightly:

Code:
if (!pPlot->isFriendly[B][COLOR="Red"]Airbase[/COLOR][/B](*this, true))
{
	return false;
}
 
Thanks for the speedy reply :goodjob: As you detected I am confused, when learning new things I use the "jump in the deep end to learn to swim method", if I start to drown I ask for help.
The part I don't understand is that you first check if the improvement is an airbase, and then you ask the plot if it's an airbase (line 3 of your 2nd code block). Did you write a new function CvPlot::isAirbase?
I did try to but didn't get it right, yes I see what you mean, :yup: yes this what I wanted to ask.
1.the plot is a friendly real city without any visible enemy units in it, or
2.the plot is a friendly airbase improvement without any visible enemy units in it.
A quick recap to clarify, the plan was to:
In the ImprovementInfos.XML add a new improvement (based on a fort), called Airbase with Airbase art files. Then add a new tag, bAirbase, (in ImprovementInfos.xml) to all improvements, (in the same way as bActAsCity makes a improvement isActAsCity)which would allow basing of Air units and paradrops from an improvement. At a later date I want to add a bSeaport tag say, which would allow basing of ships for a port improvement and figure out how to leave forts as defensive construction (while keeping its ability to placed on a resource to give you that resource). In other words to split bActAscCity up into its three constituent parts but doing it one step at a time (as I'm learning how to mod the SDK). And on top of that make it so that a city would need the airport building to station aircraft in it and make paradrops from it.

If you could bear with me a minuet, could I ask about how to get this?
  1. the plot is a friendly real city without any visible enemy units in it and has a Airport Building, or
  2. the plot is a friendly airbase improvement without any visible enemy units in it.
. I need to add both your functions, done. Now I set
Code:
"return (getPlotCity() != NULL);" 
[I]to[/I]
"return false;"
this will mean cities as they stand can't be used. Then (to allow them to be used with airport) add the xml tag bAirbase to the airport building xml. Will that work or do I have to change CvPlot::isFriendlyCity?
Code:
	if (!isAirbase(bCheckImprovement, kUnit.getTeam()))
	{
		return false;
	}
does bCheckImprovement look at buildings as well as Worker Improvements? I'll try it any way so and see what happens and get back to you. Thanks for your help again EmperorFool much appreaciated.
 
No, bCheckImprovements doesn't look at buildings. It doesn't affect how it looks at cities at all, in fact. For now you can use CvBuildingInfo::getAirUnitCapacity() or CvBuildingInfo::getAirlift() to detect the airport building. Maybe you want to add a bAirbase tag to it later.

At the end of isAirbase() you need to loop over all buildings and see if the city has one that has the tag above.

Code:
// return (getPlotCity() != NULL);  [you can remove this line]

CvCity* pCity = getPlotCity();
if (pCity)
{
	for (int iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
		CvBuildingInfo& kBuilding = GC.getBuildingInfo((BuildingTypes)iI);
		if (kBuilding.getAirUnitCapacity() > 0 && pCity->getNumBuilding((BuildingTypes)iI) > 0)
		{
			return true;
		}
	}
}

return false;
 
Right I got you, Thanks EmperorFool, I'll try that now so.....:badcomp: :hammer2: :wallbash:......

:(

Now I'm getting this now when I compile it
CvInfos.cpp|11560|error C2039: 'isAirbase' : is not a member of 'CvImprovementInfo'|
CvInfos.cpp|11561|error C2270: 'isAirbase' : modifiers not allowed on nonmember functions|
CvInfos.cpp|11562|error C2065: 'm_bAirbase' : undeclared identifier|
||=== Build finished: 3 errors, 0 warnings ===|
didn't do it the first time I compiled the cvImprovementInfos.cpp and i've not changed anything in there but code::blocks stops at
Code:
bool CvImprovementInfo::isAirbase() const
{
	return m_bAirbase; 
}
 
It sounds like you didn't add isAirbase() to CvImprovementInfo in CvInfos.h. Or the declaration in .h doesn't match the definition in .cpp.

Code:
class CvImprovementInfo : CvInfoBase
{
    ...
    [B]bool isAirbase() const;[/B]
    ...
}
 
:cringe: couldn't see the wood for the trees! I've been messing around with that SDK so much in the last week, anyway its compiled now
Thanks very much, appreciated.



So.....
I can do paradrops from a city with airport and airbase,
I can only base air units in a city with an airport and they will rebase to the airbase, until that is...the end of turn where they jump back to the city airport. they don't stay at the Airbase.

But if in the XML entry for the Airbase I put
<bActsAsCity>1</bActsAsCity>
and
<bAirbase>1</bAirbase> it works.
I wasn't going to have it so the Airbase utilizes resources in the same way as forts but I think its OK like this.
 
There is probably a check in CvUnit::doTurn() or elsewhere that checks isFriendlyCity(). You need to do a global search for that function and fix it for air units. Or live with airbases acting as cities.
 
EmperorFool is correct, there is a check for isFriendlyCity(). It's located in CvUnit::canParadrop. I edited this function to allow paradrop missions starting from any airbase that has a usable transport plane and it works fine. If you want to change the way the actual paradrop mission works, you can do that by editing CvUnit::canParadropAt.
 
I can't see a check for CvUnit::doTurn(), that checks isFriendlyCity(). and anything with isfriendlycity that is left would not seem (with my inexperienced eye) to be relevant.
I was wondering if it might be the check for the Air capacity for airport (8)
Code:
CvCity* pCity = getPlotCity();
if (pCity)
{
	for (int iI = 0; iI < GC.getNumBuildingInfos(); iI++)
	{
		CvBuildingInfo& kBuilding = GC.getBuildingInfo((BuildingTypes)iI);
		if (kBuilding.getAirUnitCapacity() > 0 && pCity->getNumBuilding((BuildingTypes)iI) > 0)
		{
			return true;
		}
	}
}

return false;
Which might be throwing it out, as the capacity for airbase is 4 (but thats only a noob's guess and probably well wide of the mark). I'd like to set the airunitcapacity to 8 for the Airbase anyway but I haven't looked at that yet,(life is making its demands on me), I'll take a look later.
By the way
Code:
CvBuildingInfo& kBuilding = GC.getBuildingInfo((BuildingTypes)iI)
is looking for Airport yes? So do all buildings have their own identifier and if so are they listed and where would I get that? Like for example Hospital.
 
EmperorFool is correct, there is a check for isFriendlyCity(). It's located in CvUnit::canParadrop. I edited this function to allow paradrop missions starting from any airbase that has a usable transport plane and it works fine. If you want to change the way the actual paradrop mission works, you can do that by editing CvUnit::canParadropAt.
Paradrops are working exactly as intended.
Code:
bool CvUnit::canParadrop(const CvPlot* pPlot) const
{
	if (getDropRange() <= 0)
	{
		return false;
	}

	if (hasMoved())
	{
		return false;
	}

	if (!pPlot->isFriendlyAirbase(*this, true))
	{
		return false;
	}
			
	return true;
}
It's getting the planes to stay at the airbase and not jump back to the city when you end the turn thats the problem.
It all works if I keep bActAsCity true as well as bAirbase. But that means the Airbase can secure a resource in the same way as the fort, a small point yes but not what I intended.
But I can live with it for now, :think: it would good to track it down though, the fort as an air base is naff and worse still is only doing paradrops from cities. Civ3's airbases were cool. planes need runways and para's need planes. So I have that now and I'm a real happy bunny.
 
I use "Air Officers". They are basically immobile land aircraft carriers. A fighter colonel holds 3 fighters, a bomber general holds 5 bombers etc.... I used the art from the standard great general for these units.

Edit: I also turned off the ability for cities to hold aircraft. But the air officers should still work with it on, as long as they have space.
 
Top Bottom