[Discussion] Sail to Europe Tag

Isabelxxx

Prince
Joined
Sep 26, 2010
Messages
399
So far I have some questions about that. Suppose you make galleons (or any other trade unit) not able to sail to Europe.
Since galleons are actually used to sell goods in Europe, disabling their ability to sail to Europe would only stop the unit in the border of the map but the AI would still try to send the unit to Europe every turn.

That's said, the AI doesn't differentiate that capability. The XML tag just disable that possibility.


At this point I consider 2 possibilities:


Units not able to sail to Europe would also need some AI adjustments:

Not allowed:
UNITAI_TRANSPORT_SEA (related to commerce) (?)

Allowed:
UNITAI_PIRATE_SEA
UNITAI_COMBAT_SEA
UNITAI_ASSAULT_SEA

That would prevent the AI to try to send those units to Europe even when that feature is disabled in the XML tag.



or

Create a new AI_COASTAL_TRADE or change the existing UNITAI_TRANSPORT_SEA, to check if the unit hast the ability of sailing to Europe:

0 (No) Then the AI would only use that unit to trade between colonies, transport of goods, etc...

1 (Yes) Just like usual.
 
Woah, be careful here ...
Messing with the UnitAIs is probably the best method to get game crashes or AI deadlocks.

I suggest you read very very carefully in DLL, how the UnitAIs are used before doing changes here. :thumbsup:
 
That's why I suggested to disable that unitAI_transport_sea in unit_info.xml for those units which are not allowed to sail to Europe.

The problem should be solved without messing with the DLL but then I have doubts about what will be the uses of those units...

Would be possible to maintain coastal trade for the AI?
Unit transport? (This seems to be related with assault_AI)

...

So far, without changing anything in the DLL we could simplify things for the AI while maintaining some complex features for the user.

AI would use those cheap light ships as unit transport, pirate units or defensive coastal units while the "big" ships would ONLY be used for trade purposes. That's a big change. We only want 1 or 2 types of units traveling to Europe, so if those units have only one purpose for the AI, it will be fulfilled better. The user could still use the trade unit in any way.

Therefore there would be a limit: we could not force the AI to use these light ships also for trading purposes amongst the colonies and those ships able to seal to Europe for trading in Europe.

On the other hand, these XML changes should improve how the AI manages the ships and the economy so anyway -even having that limit- there should be an improvement.
 
I am sorry to say, but you have a wrong idea, how UnitAIs work.

It is not that simpel:

UNITAI_TRANSPORT_SEA --> Only for trade / transport
UNITAI_COMBAT_SEA --> Only for combat
UNITAI_PIRATE_SEA --> Only piracy

The logic for UnitAIs is very situation specific.
(A UnitAI is a set of different behaviours for different situations.)

Seriously, do not mess with the UnitAIs (either in DLL or XML) without completely having read and understood the DLL sources considering this aspect.
If you don't know exactly what you are doing, your chances of causing crashes, AI deadlocks or AI to be absolutely helpless are extremely high.

You have been warned. :)
 
I also limited the movements of some units to "coastal" tiles, but that adds a huge limit to most ships.

Do you think there is other way to have ships not able to travel to Europe with real use by the AI?
 
I am sorry to say, but you have a wrong idea, how UnitAIs work.
I really suggest you read the code in sources for DLL. :thumbsup:

It is not that simpel:

UNITAI_TRANSPORT_SEA --> Only for trade / transport
UNITAI_COMBAT_SEA --> Only for combat
UNITAI_PIRATE_SEA --> Only piracy

The logic for UnitAIs is very situation specific.

Seriously, do not mess with the UnitAIs (either in DLL or XML) without completely having read and understood the DLL sources.
You have been warned. :)

Ok, but you can specify which AI should be disabled for an specific unit in XML. So even being situation specific you can put some restrictions. Don't you?

Anyway I will no be doing anything before taking a look at the DLL, just discussing the possibility.
 
Ok, but you can specify which AI should be disabled for an specific unit in XML.
So even being situation specific you can put some restrictions. Don't you?

Yes, but you should really understand what you are doing.
Otherwise the results will probably not be what you want / expect.

Examples:
UNITAI_PIRACY does not mean that the unit will never sail to Europe.
UNITAI_PIRACY without having HiddenNationality might cause serious bugs.
Removing UNIAT_TRANSPORT from a ship that is designed for Transport (by its other XML settings), might cause AI deadlocks or CTDs.
...

From what I read what you want, simply changing XML will not solve this.
You will need to change DLL and also adjust UnitAIs to handle these changes then.

What will not work:

1. Simply removing capability for a ship to sail to Europe in DLL. --> You will create totally helpless AI if you don't teach AI how to handle this then by adjusting UnitAIs.
2. Simply changing allowed UnitAIs in XML. --> You will probably also create helpless AI and risk CTDs.

Anyway I will no be doing anything before taking a look at the DLL, just discussing the possibility.

:thumbsup:

The only real possibility you will probably have is

1. Creating a new XM tag <bCanSailToEurope> (XML and Schema)
2. Lock sailing to Europe by reading this tag (DLL)

and

Either
3A. Adjust all existing UnitAIs of Ships that can have this tag (DLL)
or
3B. Create a new UnitAI for Ships that can have this tag (DLL and XML) and give it to those ships (XML)

This is not easy and messing with UnitAIs really is dangerous because it is incredibly easy to oversee some case / situation.
But it will probably be the only solution, if you really want that feature (Ships that cannot sail to Europe).
 
disabling their ability to sail to Europe would only stop the unit in the border of the map but the AI would still try to send the unit to Europe every turn.
I don't think it works like that.
I must check but before to try to send the unit, the unit check if it can sail to Europe (with the crossOcean function). As your coastal units can't cross ocean, I think there will have no problems. To justify my mind, we can see this code in the method
Code:
	if (!GET_PLAYER(getOwnerINLINE()).canTradeWithEurope())
	{
		return false;
	}
When IA can't trade with Europe (like in the revolution), they don't send their units :). So I think it will work.
 
I'm also unsure, like you M07. I have taken a look at the DLL and there are some points where the AI checks if the unit can cross the ocean.

Probably adding only the XML tag will not work but making it work as inteded should not be so difficult, maybe there are other solutions. We should try to circumvent messing with AIs as much as possible.

I also think we could try to solve it by making some changes in the crossOcean function.

As your coastal units can't cross ocean, I think there will have no problems. To justify my mind, we can see this code in the method

In fact, the unit can cross ocean until you try it, the game calls your function and then it tells you the opposite. That unit has sealing to Europe disabled but that is only known when you try to send it to Europe... don't know if you follow me.
The ship can cross ocean tiles so it will to the border of the map because that ship can travel to Europe up to the moment when you try to send it and then our function "reads" the tag and avoid that possibility.

That's said, it will not work by default. You will actually need to modify the function so the AI understand it can't trade with Europe with this unit even before trying it, just by reading the tag.

Therefore we need 2 changes:

1) Create our function to disable "Sail to Europe".
If crossOcean function does it, we only need to modify that function to also check the tag.

2)Modify the method the AI is using to check if the unit can trade with Europe.
Again, if crossOcean is modified and this same function is also used as a check then 2) is made along with 1).
 
I understood what you want, but not why!
Why do you want to have the information that you can't sail to Europe only when the unit is on an ocean plot?
 
No, i don't want it. The AI does.

How would you implement the "sail to Europe" tag?

1) Adding the XML tag.
2) New function in DLL. When you send an unit to the border you call the new function; if the tag is set to 1 the unit can travel to Europe, otherwise do nothing.



That's how I have understood you would implement it. But then the AI would do strange things...

The AI doesn't know that the unit can not seal to Europe until it has tried to send the unit to Europe. That's why I say that you need to tell the AI that the unit can not cross ocean before sending it to the border, even before any action. So the unit should not be considered as "available" for trade purposes or unit transport between Europe and the colonies, even when that is not possible if the AI sends the unit to the bord.

I mean: imagine the AI is a child. The child wants a sweet, but the shop is closed. There are 2 possibilities:
the child goes to the shop, he sees the shop is closed, he returns to home and then he tries again. A loop.
you can tell the child that the shop is closed, he stays in home. Therefore he doesn't go to the shop, so you have not lost that time.

I think you have misunderstood what I wrote.
 
Ok, indeed I misunderstood what you wrote. Before to send unit to Europe, IA checks if the unit can cross ocean with a plot equals to null. The signature method is
Code:
void canCrossOcean(CvPlot* pPlot);
Even if the unit is not in an ocean plot, the IA can know if the unit can cross ocean if we call the previous with pPlot equals to null.
 
Would that prevent the AI to consider ships with the tag as units that can cross the ocean?

I didn't fully understood what you wrote but if that solves the problem, it's ok.
 
@M07 and Isabelxxx:

You should really consider carefully what you are doing with this.

If you take away abilitiy to Sail to Europe for some ships, you might totally ruin your AI.

AI might eventually buy or build too many ships of these types and not have enough ships to sail to Europe to sell goods or transport Units.
Also, the chances of AI ships running into deadlocks are very very high, if you don't take care of UnitAIs.
When thinking about this a little deeper, we could probably find even more potentially dangerous aspects ...

Something like this can turn a great mod into a mod that is not playable anymore because AI is helpless.
Seriously, what you are talking here is extremely dangerous without adjustments to UnitAIs and PlayerAI. :dunno:
 
@M07 and Isabelxxx:

You should really consider carefully what you are doing with this.

If you take away abilitiy to Sail to Europe for some ships, you might totally ruin your AI.

AI might eventually buy or build too many ships of these types and not have enough ships to sail to Europe to sell goods or transport Units.
Heh I already thought that. There is a reason to consider the addition of these units, they will only be available in the colonies but not in Europe. Some checks I planned to add:

1) Units with the tag can not be bought in Europe.
2) Put a limit in the availability of these units.
3) Cheap units. The aim is to have the AI doing the same but with a few more units in the map performing other actions. These units will be given to the AI likely with no cost.

Again I want to make clear what's the point of this. The idea is not to mess with the existing AI and the existing units but create a few units with minimal possibilities to provoke problems but some great improvements.

Also, the chances of AI ships running into deadlocks are very very high, if you don't take care of UnitAIs.
When thinking about this a little deeper, we could probably find even more potentially dangerous aspects ...

Something like this can turn a great mod into a mod that is not playable anymore because AI is helpless.
Well, it has to be tested. I see your point but I don't fully understand your fear when these changes -if properly done- are really limited.

There are actually units which are not able to seal to Europe, at least that's what the AI considers at some points. We only want to put these new units in one of those cases. That doesn't have to conflict with the AI in any way since the AI is still using the same behaviours already present in game. But that's said, this will only work if it ¡s properly done. We have to check what are the AI requirements before sending units to Europe, since not all units are considered for this.
See that the problems will come if the unit is a potential choice for the AI but we disable that choice ad hoc. The idea here is to "taught" the AI that these units have not to be considered since the beginning when any action requires sending the unit to Europe.
 
For the next version, one of the main goal will be to upgrade IA.
They are helpless because they don't know how to use my cannons.
So, I will do a lot of checks and I don't think it will be dangerous for the IA.
I begin to really understand how it works :).
 
Great. In that case you could create a new thread with some explanation about the changes you have planned to make.

Too many suggestions come to mind...
 
CvUnit.cpp

Code:
bool CvUnit::canAutoCrossOcean(const CvPlot* pPlot) const
{
	if (canCrossOcean(pPlot, UNIT_TRAVEL_STATE_TO_EUROPE))
	{
		return false;
	}

	if (!GET_PLAYER(getOwnerINLINE()).canTradeWithEurope())
	{
		return false;
	}

	if (getDomainType() != DOMAIN_SEA)
	{
		return false;
	}

	if (!pPlot->isEuropeAccessable())
	{
		return false;
	}

	/*** Can sail to europe? ***/
	if (m_pUnitInfo->isNoCrossOcean())
	{
		return false;
	}
	/**************************************/

	return true;
}

bool CvUnit::canCrossOcean(const CvPlot* pPlot, UnitTravelStates eNewState) const
{

	if (getTransportUnit() != NULL)
	{
		return false;
	}

	/*** Can sail to europe? ***/
	if (m_pUnitInfo->isNoCrossOcean())
	{
		return false;
	}
	/**************************************/

	if (getUnitTravelState() == NO_UNIT_TRAVEL_STATE && !canMove())
	{
		return false;
	}

	switch (getUnitTravelState())
	{
	case NO_UNIT_TRAVEL_STATE:
		if (eNewState != UNIT_TRAVEL_STATE_TO_EUROPE)
		{
			return false;
		}
		if (!GET_PLAYER(getOwnerINLINE()).canTradeWithEurope())
		{
			return false;
		}
		break;
	case UNIT_TRAVEL_STATE_IN_EUROPE:
		if (eNewState != UNIT_TRAVEL_STATE_FROM_EUROPE)
		{
			return false;
		}
		break;
	default:
		FAssertMsg(false, "Invalid trip");
		return false;
		break;
	}

	FAssert(pPlot != NULL);
	if (!pPlot->isEurope())
	{
		return false;
	}

	return true;
}

"CvGameTextMgr.ccp"

Code:
	if (kUnitInfo.isRivalTerritory())
	{
		szBuffer.append(NEWLINE);
		szBuffer.append(gDLL->getText("TXT_KEY_UNIT_EXPLORE_RIVAL"));
	}
	if (kUnitInfo.isFound())
	{
		szBuffer.append(NEWLINE);
		szBuffer.append(gDLL->getText("TXT_KEY_UNIT_FOUND_CITY"));
	}
	/*** Can sail to europe? ***/
	if (kUnitInfo.isNoCrossOcean())
	{
		szBuffer.append(NEWLINE);
		szBuffer.append(gDLL->getText("TXT_KEY_UNIT_NO_CROSS_OCEAN"));
	}
	/**************************************/


"CvInfos.cpp"

Code:
m_bTreasure(false),
m_bCapturesCargo(false),
m_bLandYieldChanges(false),
m_bWaterYieldChanges(false),
/***  Can sail to europe?  ***/
m_bNoCrossOcean(false),
/**************************************/


Code:
bool CvUnitInfo::isWaterYieldChanges() const
{
	return m_bWaterYieldChanges;
}

/***  Can sail to europe?  ***/
bool CvUnitInfo::isNoCrossOcean() const
{
	return m_bNoCrossOcean;
}
/**************************************/

Code:
	stream->Read(&m_bLineOfSight);
	stream->Read(&m_bHiddenNationality);
	stream->Read(&m_bAlwaysHostile);
	stream->Read(&m_bTreasure);
	stream->Read(&m_bCapturesCargo);
	stream->Read(&m_bLandYieldChanges);
	stream->Read(&m_bWaterYieldChanges);
	/***  Can sail to europe?  ***/
	stream->Read(&m_bNoCrossOcean);
	/**************************************/

Code:
	stream->Write(m_bTreasure);
	stream->Write(m_bCapturesCargo);
	stream->Write(m_bLandYieldChanges);
	stream->Write(m_bWaterYieldChanges);
	/***  Can sail to europe?  ***/
	stream->Write(m_bNoCrossOcean);
	/**************************************/

Code:
	pXML->GetChildXmlValByName(&m_bCapturesCargo,"bCapturesCargo",false);
	pXML->GetChildXmlValByName(&m_bLandYieldChanges,"bLandYieldChanges",true);
	pXML->GetChildXmlValByName(&m_bWaterYieldChanges,"bWaterYieldChanges",true);
	/***  Can sail to europe?  ***/
	pXML->GetChildXmlValByName(&m_bNoCrossOcean, "bNoCrossOcean", false);
	/**************************************/

"CvInfos.h"

Code:
	DllExport bool isLandYieldChanges() const;
	DllExport bool isWaterYieldChanges() const;
	/***  Can sail to europe?  ***/
	DllExport bool isNoCrossOcean() const;
	/**************************************/

Code:
	bool m_bCapturesCargo;
	bool m_bLandYieldChanges;
	bool m_bWaterYieldChanges;
	/***  Can sail to europe?  ***/
	bool m_bNoCrossOcean;
	/**************************************/

"CIV4UnitSchema.xml"

Code:
	<ElementType name="bAlwaysHostile" content="textOnly" dt:type="boolean"/>
	<ElementType name="bTreasure" content="textOnly" dt:type="boolean"/>
	<!-- Can sail to europe? -->
	<ElementType name="bNoCrossOcean" content="textOnly" dt:type="boolean"/>
	<!-- -->

Code:
		<element type="bTreasure"/>
		<!-- Can sail to europe? -->
		<element type="bNoCrossOcean" minOccurs="0"/>
		<!-- -->
 
I remembered that feature was planned some time ago for Triangle Trade...

No AI problems, the unit can not sail to Europe and the AI will know it (see CvUnit.cpp).
 
Yep, this is what I thought to do, except the functions name. It is not hard as you can see :).
@isabelxxx I invite you again to git, because I changed the repository.
 
Top Bottom