View Full Version : Case Study: How to make multi-domain units
Kael Apr 13, 2006, 07:19 PM 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:
case DOMAIN_LAND:
if (pPlot->isWater())
{
if (bIgnoreLoad || !isHuman() || plot()->isWater() || !canLoad(pPlot))
{
return false;
}
}
break;
Changed to:
case DOMAIN_LAND:
if (pPlot->isWater() && !canMoveImpassable())
{
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:
case DOMAIN_LAND:
if (pPlot->area() == area())
{
return true;
}
break;
Changed to:
case DOMAIN_LAND:
if (pPlot->area() == area() || canMoveImpassable())
{
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:
if (plot()->isWater())
{
getGroup()->pushMission(MISSION_SKIP);
return;
}
Changed to:
if (plot()->isWater() && !canMoveImpassable())
{
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:
case DOMAIN_LAND:
case DOMAIN_IMMOBILE:
return !(isWater());
break;
Changed to:
case DOMAIN_LAND:
return true;
break;
case DOMAIN_IMMOBILE:
return !(isWater());
break;
Civmansam Apr 13, 2006, 07:51 PM Yay! Now my Quarren can move on land and water!
Any Idea on how to change animations when they are in water?
Can you do the same thing with air?
Kael Apr 13, 2006, 07:54 PM Yay! Now my Quarren can move on land and water!
Any Idea on how to change animations when they are in water?
Can you do the same thing with air?
The problem is that the Domain types control a lot more than the units movement abilities. I was kinda surprised when I started digging into it. I assumed they just determined what plots they could enter, but there is a ton of AI work that is dependant on the domain type too (which is why I don't have my fireballs as DOMAIN_AIR units).
Shqype Apr 13, 2006, 11:36 PM Did I miss something, or with the above code can the unit still move through mountains?
Kael Apr 14, 2006, 03:56 AM Did I miss something, or with the above code can the unit still move through mountains?
Yeah, bCanMoveImassable will still do everything it did, plus allow travel over water tiles.
The Great Apple Apr 14, 2006, 05:20 AM Another nice little tidbit here.
Rabbit, White Apr 14, 2006, 07:30 AM Very nice indeed.
NeverMind Apr 14, 2006, 03:42 PM That's very interesting, Kael! Thanks! :thumbsup:
I'm waiting for new Case Studies from you :)
Kael Apr 14, 2006, 03:46 PM That's very interesting, Kael! Thanks! :thumbsup:
I'm waiting for new Case Studies from you :)
I am more than happy to share what I have, im excited to see others posting their tips and tricks as well.
12monkeys Apr 16, 2006, 06:50 AM Is it also possbile to creat new domain?
Something like a DOMAIN_AMPHIB which combines sea and land domains. Or a DOMAIN_SUBMARINE which would allow to create a submaritime world.
It might be easier to to create some new domains, instead of combining several existing ones.
Zurai Apr 16, 2006, 04:25 PM Is it also possbile to creat new domain?
Something like a DOMAIN_AMPHIB which combines sea and land domains. Or a DOMAIN_SUBMARINE which would allow to create a submaritime world.
It might be easier to to create some new domains, instead of combining several existing ones.
Yes, that should be possible and not too difficult. I plan on doing a DOMAIN_AMPHIBIOUS for my mod, as one of the races (lizardmen) can swim in coastal waters and there are some other units for which the trait would be useful (water elementals, pearl giants, and a few other things).
The only thing is you then have to go through the code and find wherever it references DOMAIN_LAND or DOMAIN_WATER and add in cases for DOMAIN_AMPHIBIOUS. I'm not terribly looking forward to that.
HP_Ganesha Apr 17, 2006, 02:24 PM very good kael!!! And Put a city in a water like a "Atlanta" is possible??
Kael Apr 17, 2006, 04:32 PM very good kael!!! And Put a city in a water like a "Atlanta" is possible??
Ive been out of america for a few weeks now, did something happen to Atlanta?!? :D
Seriously, yes. You could tie this function to a promotion instead of bMoveImpassablelike I did and give that promotion to every unit of a civ to create a "merman" civ if you wanted.
HP_Ganesha Apr 19, 2006, 07:21 AM well I think Atlanta of American Dont Change nothing... ¬¬, but i dont be in USA if Atlanta change in a few days I the last person a know this...hehe...
Well Is only a litle question i dont realy need this mod... but tks anyway
phatlip May 31, 2006, 04:29 PM I tried to achieve the same thing by adding a new DOMAIN to the xml.
There are all the spots where DOMAIN_<TYPE> are used hwere you have your own domain, but also and very importantly, you need to add the DOMAIN to CvEnums.h under enum DomainTypes.
My code works perfectly in game, but i get an XML error on launch - found where the game prints that error but i just keep diggin further into the rabbit hole and not finding where else i need to tell the game about the DOMAIN type.
Anyone else have any luck?
The Great Apple May 31, 2006, 04:38 PM I have successfully added new domains in the XML. If you can't work out what's up I'll see if I can dig up the files and give you some pointers.
Lord Olleus May 31, 2006, 04:57 PM I tried to achieve the same thing by adding a new DOMAIN to the xml.
There are all the spots where DOMAIN_<TYPE> are used hwere you have your own domain, but also and very importantly, you need to add the DOMAIN to CvEnums.h under enum DomainTypes.
My code works perfectly in game, but i get an XML error on launch - found where the game prints that error but i just keep diggin further into the rabbit hole and not finding where else i need to tell the game about the DOMAIN type.
Anyone else have any luck?
by guess is that there is a schema somewhere which needs altering.
phatlip May 31, 2006, 07:51 PM I have successfully added new domains in the XML. If you can't work out what's up I'll see if I can dig up the files and give you some pointers.
So far i have modified:
CvUnit.cpp
-> canMoveInto() // added DOMAIN to list of conditionas for move
CvEnums.h
-> enum DomainTypes // added DOMAIN as index #4
CvUnitAI.cpp
-> // edited AI to use DOMAIN units like land units even at sea
CvPlot.cpp
-> // made the plot a valid action for DOMAIN
Like i mentioned, the game works fine. Perhaps i am missing a declaration in CVInfos.cpp (or .h)
Or perhaps you need to define DOMAINS somewhere in the XML? I can't find anywhere i'm missing something yet, but the error comes from a method in XMLLoadUtility.cpp - so i'm following the function trail. It leads me to CvGlobals::getUnitInfo(DomainTypes e). Thats returns a CvInfoBase pointer. Continue searching and i find that CvInfoBase works off a hash_map for fast searching.
So now i just need to find how that has_map is populated and get my DOMAIN in there, obviously Great Apple has found this already - and since i'm at work and can't stare at my precious SDK code, can you give me a hint?
phatlip May 31, 2006, 09:03 PM 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:
case DOMAIN_LAND:
case DOMAIN_IMMOBILE:
return !(isWater());
break;
Changed to:
case DOMAIN_LAND:
return true;
break;
case DOMAIN_IMMOBILE:
return !(isWater());
break;
Not entirely the correct way to do it. This will mean that using the goto (or right click) will show a water tile as a valid move for any land unit. It won't crash the game, but it isn't very 'polished'.
simple change though, just use this code instead:
case DOMAIN_LAND:
return (!isWater() || canMoveImpassable());
break;
case DOMAIN_IMMOBILE:
return !(isWater());
break;
The Great Apple Jun 01, 2006, 02:23 AM Or perhaps you need to define DOMAINS somewhere in the XML? I can't find anywhere i'm missing something yet, but the error comes from a method in XMLLoadUtility.cpp - so i'm following the function trail. It leads me to CvGlobals::getUnitInfo(DomainTypes e). Thats returns a CvInfoBase pointer. Continue searching and i find that CvInfoBase works off a hash_map for fast searching.Yes, you do. This is what I had thought you meant at the start of your first post!
CIV4BasicInfos.xml
Under the tag <DomainInfos>. They need to be the same order as the enums.
That should work.
phatlip Jun 01, 2006, 03:20 AM Yes, you do. This is what I had thought you meant at the start of your first post!
CIV4BasicInfos.xml
Under the tag <DomainInfos>. They need to be the same order as the enums.
That should work.
bah so simple, and here's my trawling through the SDK. I actually had kinda of figured it out, reading through the xml stream stuff was pretty intersting, still hadn't found the file or exact method of collecting the data.
From what i can gather it pretty much picks up every single xml file and read through all the tags, picking up every value you put there - which would explain why it worked at the game level, but just threw a little debugging error.
zulu9812 Jun 01, 2006, 03:29 AM Many thanks for doing this. Just the other day, I was thinking "We need How To tutorials on specific tasks: that would really help out those less confident". So thanks again. Do you think that you'll be doing any more?
phatlip Jun 01, 2006, 03:59 AM sure i'm planning a complete write up of my new-styled gunship, that will fly over water, land on carriers and die at sea (can't land on ocean eh.) No more loading them into transports either, thats kinda bogus.
RogerBacon Jun 01, 2006, 08:38 AM I wish I had seen this thread before doing my <bFlying> mod, although I still would have added a new tag rather than reuse an existing one, just for the epexrience of doing it.
Kael,
There are a few more things I think you need to do that you didn't mention in the tutorial. Did you check combat of your land units over water? You may find some unintended effects. I'm at work now so I don't have the code with me but you can download my flying mod and look at what I did there.
I found that there is a section of the SDK that checks if a unit can defend and if it can't defend it alway loses the battle. Land units, be default, can't defend on a water tile. so, I noticed that my gunships would die to a simple galley 100% of the time. You need to change the canDefend() function in the SDK. Also, are you seeing combat odds when you hold down the alt key before an attack? I remember I had to change something else so that the combat odds would show up. Good work on the tutorial though.
Roger Bacon
Kael Jun 01, 2006, 05:22 PM I wish I had seen this thread before doing my <bFlying> mod, although I still would have added a new tag rather than reuse an existing one, just for the epexrience of doing it.
Kael,
There are a few more things I think you need to do that you didn't mention in the tutorial. Did you check combat of your land units over water? You may find some unintended effects. I'm at work now so I don't have the code with me but you can download my flying mod and look at what I did there.
I found that there is a section of the SDK that checks if a unit can defend and if it can't defend it alway loses the battle. Land units, be default, can't defend on a water tile. so, I noticed that my gunships would die to a simple galley 100% of the time. You need to change the canDefend() function in the SDK. Also, are you seeing combat odds when you hold down the alt key before an attack? I remember I had to change something else so that the combat odds would show up. Good work on the tutorial though.
Roger Bacon
Yeah, its just an example. We canged the canDefend algo too. Nowdays FfH uses a promotion to control if a land unit can travel over water or not. So the ability can be added and removed dynamically.
Ingvina Freyr Jun 02, 2006, 07:53 AM So here's a question from a mod-chieftain to all the mod-deitys out there.
I wouldn't want to start changing any codes myself. Considering my lack of knowledge in this area I'm afraid to "mess thing up". Is there a possibility for you to create a file for me and others to download and replace an old file with? (Thats about how far I would dare to go at the moment.:))
I courious to see if a small boat with a carrying-capacity, that could travel rivertiles and coastal tiles, would be a good adding to the game.
Kael Jun 02, 2006, 08:00 AM So here's a question from a mod-chieftain to all the mod-deitys out there.
I wouldn't want to start changing any codes myself. Considering my lack of knowledge in this area I'm afraid to "mess thing up". Is there a possibility for you to create a file for me and others to download and replace an old file with? (Thats about how far I would dare to go at the moment.:))
I courious to see if a small boat with a carrying-capacity, that could travel rivertiles and coastal tiles, would be a good adding to the game.
Unfortunatly the files contain multiple changes so a modified file will only be helpful against a vanilla civ build. This write-up was done more to help new SDK developers than to be used (the article was released on the same day as the SDK).
If you want just multi-domain units on a vanilla build I would recommend using RogerBacon's bFlying modpack, which gives you all fo this functionality without having to do the programming yourself.
seady Oct 26, 2006, 02:25 AM Ive been out of america for a few weeks now, did something happen to Atlanta?!? :D
Amy: So, Fry, Atlanta was an American city in your time?
Fry: I think it was just an airport. They had a place where you could buy nuts.
Umbriel: No! Ancient Atlanta was more than just a Delta hub. It was a vibrant metropolis, the equal of Paris or New York.
Fry: That's right, honey! Whatever you say.
Umbriel: Look at these fabulous ruins. Turner Field, the Coca-Cola bottling plant, the, uh, the airport.
Leela: But tell us, how could a city with such a ... fabulous airport end up underwater?
Colonel: Ah, now that's a story that can only rightly be told in a Chamber of Commerce video narrated by folk-rock troubadour Donovan.
troyDoogle7 Jan 12, 2007, 07:07 AM Hi guys.
I would like to use this for my smac mod to make gravships.
For those of you that know about Alpha Centauri, Would this be the best way to achieve gravships, as well as locusts of chiron?
If anyone would like to help out with this, I would be most grateful.
Kael Jan 12, 2007, 02:11 PM Hi guys.
I would like to use this for my smac mod to make gravships.
For those of you that know about Alpha Centauri, Would this be the best way to achieve gravships, as well as locusts of chiron?
If anyone would like to help out with this, I would be most grateful.
Probably, if you want those ships to be able to cross over land and water tiles this is what you want.
strategyonly Jan 13, 2007, 12:27 AM deleted......
Ultraman Mar 15, 2007, 05:44 AM Hi Kael!
Thanx for a great tutorial. Have tried to follow exactly the instructions you have given, unfortunately my Gunship is still gunshy! Wanted a Gunship that would take out units along the coast. Have changed the unit specs to canmoveimpassable; however made oceans still impassable. Is there something I am missing, please? Thanx!
Yakk Mar 22, 2007, 04:01 PM Did you compile and use the resulting DLL? This is an easy mistake to make.
One way to check this is to pop up a window, write to a file on your hard drive with a time stamp, or otherwise create a visible effect that you can detect.
Can you go over and check each change Kael listed, and make sure it is in the code? Missing one or two could easily make Kael's solution not work.
Ultraman Mar 22, 2007, 10:01 PM Hi Yakk! Thanx for replying.
You mean that after editing the ccp files, I still need to compile the DLL? Damn! I was hoping to avoid that. I'm no programmer.
Yakk Mar 23, 2007, 07:41 AM *laugh*
Tech Support Rule 1: First ask the person if the computer is plugged in!
Yes. .cpp files are simply instructions to the computer on how to build an executable (.exe) or dynamic link library (.dll) or other pile of compiled computer code.
GyroLeader Apr 14, 2007, 02:29 AM I couldn't get it work, so could someone send me some example files or something. I really would like to use this.
strategyonly May 19, 2007, 08:52 AM since nobody wanted to help, had someone else do it!
Kael Jul 18, 2007, 05:03 PM Note, this is no longer required with BtS, all you have to do is set the bCanMoveAllTerrain attribute on the unit to do this.
strategyonly Jul 18, 2007, 06:59 PM Note, this is no longer required with BtS, all you have to do is set the bCanMoveAllTerrain attribute on the unit to do this.
fantastic, now if WE (you) could get them to do the animal to enter territory, we'd be all set!!!:p
Kael Jul 18, 2007, 09:39 PM fantastic, now if WE (you) could get them to do the animal to enter territory, we'd be all set!!!:p
Yeah, I worked around this in AoI by creating a new unitcombat type (UNITCOMBAT_ANIMAL) and switching all the animals from bAnimal to UNITCOMBAT_ANIMAL. Then instead of giving units bonuses against animals they just got bonuses vs the UNITCOMBAT_ANIMAL type (so it worked out the same). And since the animals technically weren't "animals" they don't have any border restrictions.
The only problem is that it also means they won't spawn as animals do in the world. Not a problem if you are making a scenario and can place them manually on the map, but it is a concern for random maps.
In early versions I had a check in the new canmoveinto python function that would stop barbarian owned animals from entering owned tiles, but by the end I remover it just because dangerous threatening animals match the flavor of AoI better.
But the short answer is that your right. I wish that the "border" restriction was only applied to barbarian controlled animals instead of the whole batch.
strategyonly Jul 18, 2007, 10:03 PM Now is this "work around" in the BtS or the regular Vanilla game??
Kael Jul 19, 2007, 08:25 AM Now is this "work around" in the BtS or the regular Vanilla game??
This was all BtS stuff.
|
|