Note, this is no longer required with BtS, all you have to do is set the bCanMoveAllTerrain attribute on the unit to do this
This was one of the first changes I made with the SDK. I wanted units that were able to travel over land and water tiles without being air units. I thought it would be a simple change, but I came to realize that it is easy to change things with the SDK and really hard to get the AI to use those changes.
For specific implementation I decided to use the bCanMoveImpassable attribute, if this attribute is set the unit would be able to travel over all land and water tiles. Then I could block the terrains I didn't want with the bTerrainImpassable attribute. I don't know if its nessesarily the best way to do it, if I was going to start again I might make a new attribute to control it, or trigger it off of a promotion. I would hope that this writeup makes it clear enough that you are able to implement multi-domain units in your own mods in whatever specific implementation works best for you.
Step 1: Give units with bCanMoveImpassable the ability to cross water tiles
Woohoo, this seems so easy. There is a function that controls what plots a unit is allowed to enter. If it is a water tile and the unit isn't getting into cargo it returns false. I add an additional check to see if the unit is canMoveImpassable and I am done, right? Unfortunatly no, but its a start.
CvUnit.cpp CvUnit::canMoveInto:
Original code:
Changed to:
Step 2: Teaching an old dog new tricks
Okay, now the units have the ability to travel across water tiles but the AI refused to use the ability. Units dumped in the middle of the ocean would just sit there. Barbarians wouldn't cross water tiles to attack undefended cities or defend their own.
Turns out there is a seperate function that the AI uses to decide what plots it can enter, its AI_plotValid(). As far as I can tell area() means its a land mass, the change means that instead of just checking to make sure the target plot is land, it returns true if the plot is land or the unit has bCanMoveImpassable.
CvUnitAI.cpp CvUnitAI::AI_plotValid():
Original Code:
Changed to:
Now the AI kinda used water tiles. It would cross them if I dropped it on a water tile, but it still wouldn't cross water to get to stuff. Back into the SDK and there is another function that controls what missions are passed to units, AI_Update.
CvUnitAI.cpp CvUnitAI::AI_Update():
Original Code:
Changed to:
Step 3: My Dog has fleas!
Now it all works perfectly... almost. Testing showed (despite the experience of people that play FfH I actually do test, quit laughing, yes I mean you Woodelf) that everything was working as planned except the units were losing all of their movement points whenever they crossed a water tile. So no matter how many movement points they had they could only move 1. I actually don't know what the below does, I just noticed that DOMAIN_LAND and DOMAIN_IMMOBILE seemed to do the same thing on water tiles so I gave DOMAIN_LAND its own break and it fixed it.
CvPlot.cpp CvPlot::isValidDomainForAction():
Original Code:
Changed to:
This was one of the first changes I made with the SDK. I wanted units that were able to travel over land and water tiles without being air units. I thought it would be a simple change, but I came to realize that it is easy to change things with the SDK and really hard to get the AI to use those changes.
For specific implementation I decided to use the bCanMoveImpassable attribute, if this attribute is set the unit would be able to travel over all land and water tiles. Then I could block the terrains I didn't want with the bTerrainImpassable attribute. I don't know if its nessesarily the best way to do it, if I was going to start again I might make a new attribute to control it, or trigger it off of a promotion. I would hope that this writeup makes it clear enough that you are able to implement multi-domain units in your own mods in whatever specific implementation works best for you.
Step 1: Give units with bCanMoveImpassable the ability to cross water tiles
Woohoo, this seems so easy. There is a function that controls what plots a unit is allowed to enter. If it is a water tile and the unit isn't getting into cargo it returns false. I add an additional check to see if the unit is canMoveImpassable and I am done, right? Unfortunatly no, but its a start.
CvUnit.cpp CvUnit::canMoveInto:
Original code:
Code:
case DOMAIN_LAND:
if (pPlot->isWater())
{
if (bIgnoreLoad || !isHuman() || plot()->isWater() || !canLoad(pPlot))
{
return false;
}
}
break;
Changed to:
Code:
case DOMAIN_LAND:
if (pPlot->isWater()[b] && !canMoveImpassable()[/b])
{
if (bIgnoreLoad || !isHuman() || plot()->isWater() || !canLoad(pPlot))
{
return false;
}
}
break;
Step 2: Teaching an old dog new tricks
Okay, now the units have the ability to travel across water tiles but the AI refused to use the ability. Units dumped in the middle of the ocean would just sit there. Barbarians wouldn't cross water tiles to attack undefended cities or defend their own.
Turns out there is a seperate function that the AI uses to decide what plots it can enter, its AI_plotValid(). As far as I can tell area() means its a land mass, the change means that instead of just checking to make sure the target plot is land, it returns true if the plot is land or the unit has bCanMoveImpassable.
CvUnitAI.cpp CvUnitAI::AI_plotValid():
Original Code:
Code:
case DOMAIN_LAND:
if (pPlot->area() == area())
{
return true;
}
break;
Changed to:
Code:
case DOMAIN_LAND:
if (pPlot->area() == area()[b] || canMoveImpassable()[/b])
{
return true;
}
break;
Now the AI kinda used water tiles. It would cross them if I dropped it on a water tile, but it still wouldn't cross water to get to stuff. Back into the SDK and there is another function that controls what missions are passed to units, AI_Update.
CvUnitAI.cpp CvUnitAI::AI_Update():
Original Code:
Code:
if (plot()->isWater())
{
getGroup()->pushMission(MISSION_SKIP);
return;
}
Changed to:
Code:
if (plot()->isWater()[b] && !canMoveImpassable()[/b])
{
getGroup()->pushMission(MISSION_SKIP);
return;
}
Step 3: My Dog has fleas!
Now it all works perfectly... almost. Testing showed (despite the experience of people that play FfH I actually do test, quit laughing, yes I mean you Woodelf) that everything was working as planned except the units were losing all of their movement points whenever they crossed a water tile. So no matter how many movement points they had they could only move 1. I actually don't know what the below does, I just noticed that DOMAIN_LAND and DOMAIN_IMMOBILE seemed to do the same thing on water tiles so I gave DOMAIN_LAND its own break and it fixed it.
CvPlot.cpp CvPlot::isValidDomainForAction():
Original Code:
Code:
case DOMAIN_LAND:
case DOMAIN_IMMOBILE:
return !(isWater());
break;
Changed to:
Code:
case DOMAIN_LAND:
[b]return true;
break;[/b]
case DOMAIN_IMMOBILE:
return !(isWater());
break;