[MOD] Colonization: 2071

Ok, sounds good. :goodjob: I didn't know so many of the yield names had instances of being hardcoded somewhere in the DLL.. Even if using a single enum for yield names, it would still make sense to reduce the actual hardcoding itself where possible, or at least know the details of what the hardcoding is doing before being able to use that yield for modmodding. For instance you wouldn't want to assign a new yield like Fiber Optics to YIELD_CLOTH, without understanding what it's doing in making hardcoded references to YIELD_CLOTH in the first place and why that was done. (Does YIELD_CLOTH now have some unique game behaviors which aren't exposed to XML, or is it also making hardcoded references to specific buildings & units content unique to M:C which we wouldn't be aware of from the current asserts?)

I'm guessing the "Narcotics"-type yields in 2071 :smoke: could be matched fairly directly with fermentable yields in M:C, ie
.value("YIELD_OPIATES", YIELD_GRAPES)
.value("YIELD_NARCOTICS", YIELD_WINE)
But it seems like these yield types can already be handled modularly with existing XML, eg <AutoSellsYields> in buildinginfos for BUILDING_TAVERN. If this is true, DLL hardcoding referring to YIELD_GRAPES and YIELD_WINE tags doesn't necessarily need to be present.
 
For instance you wouldn't want to assign a new yield like Fiber Optics arbitrarily to YIELD_CLOTH, without understanding what it's doing in making hardcoded references to YIELD_CLOTH in the first place and why that was done. (Does YIELD_CLOTH now have some unique game behaviors which aren't exposed to XML, or is it also making hardcoded references to specific buildings & units content unique to M:C which we wouldn't be aware of from the current asserts?)
I don't know which yields are hardcoded into something special either. This is where the yield group functions come into play. The idea is that one group should define one type of behavior and you can customize the behavior by selecting which groups your yield is located in. That way special meaning is defined in Yields.h only, except for really special cases. It takes a bit of investigation to define the groups correctly.

I'm guessing the "Narcotics"-type yields in 2071 :smoke: could be matched fairly directly with fermentable yields in M:C, ie
.value("YIELD_OPIATES", YIELD_GRAPES)
.value("YIELD_NARCOTICS", YIELD_WINE)
But it seems like these yield types can already be handled modularly with existing XML, eg <AutoSellsYields> in buildinginfos for BUILDING_TAVERN. If this is true, DLL hardcoding referring to YIELD_GRAPES and YIELD_WINE tags doesn't necessarily need to be present.
YIELD_GRAPES is not used outside Yields.h. However banquet is hardcoded to use YIELD_SHEEP, YIELD_CATTLE YIELD_WINE and YIELD_ALE. Doesn't look like YIELD_WINE is used for anything else. I'm not quite sure what to do about that. It's not like it looks extremely complicated.

Code:
if (ePlotCity->getYieldStored(YIELD_SHEEP) < GC.getCache_BANQUET_YIELD_AMOUNT())
{
    return false;
}
if (ePlotCity->getYieldStored(YIELD_CATTLE) < GC.getCache_BANQUET_YIELD_AMOUNT())
{
    return false;
 }
 if (ePlotCity->getYieldStored(YIELD_WINE) < GC.getCache_BANQUET_YIELD_AMOUNT())
{
    return false;
}
if (ePlotCity->getYieldStored(YIELD_ALE) < GC.getCache_BANQUET_YIELD_AMOUNT())
{
    return false;
}
return true;
There is another place where GC.getCache_BANQUET_YIELD_AMOUNT() is subtracted from each, but that's it. YIELD_WINE has no special meaning apart from this.

One solution would be to loop all yields and then have a yield group for banquet yields. That approach allows 2071 to have banquets using different resources. It doesn't look like this code is called often. Speed might not be critical, though it should be investigated.

Surprisingly it looks like the banquet is written to work in network games, though Kailric admitted he didn't even consider that at all. May fortune favor the foolish :lol:
 
ah a lot of those DLL references came from banquets, that makes sense :beer: I'm guessing the simplest solution is to use ifdef that omits that and other M:C-specific sections from modmods unless modders want to activate it, while still leaving it available in M:C. It might eventually be cool to expose that mechanism to XML, so it would be possible to mod actions that consume sets of yields. But for now its best to get to a simple codebase with minimum of hardcoding - especially if omitting that would also omit hardcoding of SHEEP CATTLE and ALE.
 
The simplest solution would be to set BANQUET_YIELD_AMOUNT to 10000 or something else equally impossible. Then make a yield group of banquet yields, which returns true to everything. That way banquets are disabled unless somebody plays 10000 of all yields to hold one. Sure XML defines only would be better, but I don't know where to place that info at the moment.

I ran into a problem. I realized I never held a banquet, don't have a savegame where I can hold one and can't quickly make a savegame to hold one to test on. I will not dare to modify the code unless I can test on it afterwards meaning I can't make a solution for the banquet right now :(
This will have to wait even though I making a group for it appears to be a minor task.
 
An update on how things are progressing.

I learned that CvCity::doYields() has hardcoded yields. I'm not touching that code as it looks rather complex. We will have to accept #ifdef there. Some day I might replace some of it with a group of yields, which has to be invented. It would be best if yields, which has to be invented before they are produced can be defined in a list somewhere instead of being hardcoded into possibly multiple files.

I'm getting into how the AI view yields. In my uncommitted code the AI's decision code for selling yields goes:
  1. If yield is raw material group, then sell unless it is needed in at least one city owned by that player.
  2. Always sell if yield is in bonus resource group. (raw material rules takes priority if yield is in both groups)
  3. YIELD_TRADE_GOODS (I haven't figured out how to get rid of this yet)
  4. Sell nothing else.
Maybe I will make some "always sell" group instead of reusing bonus resources, which also affects other AI behavior.

I say this really looks promising for adding more yields. We can add yields to list to tell how the AI should treat them without even looking into the AI code. Now that appears to be a great improvement for any mod. Remember the talk about adding more yields to M:C. It will be much easier in the near future :D

Yields I'm considering leaving in the code (needs more investigation)
YIELD_FOOD
YIELD_GRAIN (luxury food)
YIELD_LUMBER
YIELD_WEAPONS
YIELD_HORSES
YIELD_TOOLS

All virtual yields. The comment on those are
note: virtual in the sense that they can't be transported or sold
In other words those are hammers, bells etc.

Weapons appears not to be that hard to remove from the code, but what is the point in removing them? :)
The rest would stay there because they have hardcoded functions. With the exception of luxury food I don't see a point in even trying to get rid of them. Maybe luxury food can make it into 2071.
 
Yes I agree with leaving existing hardcoding alone for FOOD, LUMBER, WEAPONS, HORSES, TOOLS; these have specific functions that should be very generalizable across modmods, so it's helpful to leave them in and just keep aware of the hardcoded features when modding. All virtual yields as well as maybe YIELD_TRADE_GOODS as well could make sense to leave hardcoded; also maybe YIELD_STONE if there's existing code for using it as a construction material.

It looks like the CvUnit.cpp section for COMMAND_HOLD_FEAST involves hardcoded functions for Knights/Nobleman which occur other places too. (I guess that was part of the UNITCLASS_NOBLEMAN assert earlier.)

I'm hoping most of the trading system may also be something that can be reused by modmods without much need for mod-specific DLL (ie reusing Pedler as some form of merchant profession, adding XML placeholders for TRADING_GUILDS , TRADING_TRADE_ROUTE_2 ,TRADING_TRADEPOST and modifying as desired, with maybe a few tweaks to something like TRADE_FAIR.) It looks like almost everything else is already reasonably modular & exposed to XML. However, hardcoding of the special rules for the system of Knight/Page/Nobleman/Spice/Luxury Food is interrelated and also intertwined with many of the combat options and feasts and ransom etc. That's the one thing in M:C that would be a central challenge of trying to use it as a more general modmodding base, I'm not sure how best to deal with this though - it's not like those could all be renamed and used as is, since they're designed in a way very unique to M:C.

BTW what would go in the bonus resource group, is it yields that have a map bonus resource in bonusinfos.xml that produces some of them? I warn you I can tend to go a bit crazy adding Bonuses in 2071 (Antediluvian Catacomb or Gargantuan Fossil anyone? :p:crazyeye:) Guess I like the idea of making a wide variety of very rare / exotic special sites that you can come across in exploring uncharted planets, and feel that you've discovered something unique to that place :scan::science:
 
also maybe YIELD_STONE if there's existing code for using it as a construction material.
It doesn't appear that stone has any special code. However now that I think about it, maybe I should make a group of building materials and put lumber and stone into it. I wouldn't be surprised if the AI fails to use stone and as such the stone AI is bugged.

It looks like the CvUnit.cpp section for COMMAND_HOLD_FEAST involves hardcoded functions for Knights/Nobleman which occur other places too. (I guess that was part of the UNITCLASS_NOBLEMAN assert earlier.)
I just had an insiration. There is the function CvGlobals::getCache_DEFAULT_NOBLEMAN_CLASS(). It returns the cached content of DEFAULT_NOBLEMAN_CLASS. This mean we can code something like:
Code:
if (GC.getCache_DEFAULT_NOBLEMAN_CLASS() > 0)
{
    // some nobleman code
}
That way the code will only execute if DEFAULT_NOBLEMAN_CLASS is set to something in XML. This exploits that it will set it to 0 if the value isn't present in XML. However I'm not sure it's a wise decision for M:C performance. Maybe an #ifdef would be better. Presumably it should be #ifdef USE_NOBLEMAN_CLASS and then in a header file all files include add
Code:
#ifndef COLONIZATION2071
#define USE_NOBLEMAN_CLASS
#endif
That way we have an easy way to turn defines for each function on and off. At the same time this is done at compile time meaning the code could still contain yields and stuff only defined in M:C.

BTW what would go in the bonus resource group, is it yields that have a map bonus resource in bonusinfos.xml that produces some of them?
I'm wondering about the same thing, which is why my working changes haven't been committed yet. I made the group as it made sense to group those looking at the AI code. I named it after the comments without fully understanding why the AI group those. I'm planning on renaming it as it should be well defined what should go in there.

Looking at the other groups so far we have
Raw materials
Cities consumes some each turn (like ore or cotton)
AI sells surplus

Virtual
Anything that can't be loaded into wagon trains, such as hammers and crosses.
This is defined as hammers or anything after that as vanilla defines it like that in python. I see no reason to change that as it is working rather well.
Invert the output from this group and you get "can be loaded into a ship" group :)

I plan on adding this:
luxury goods (in lack of a better name)
AI will sell this unconditionally. Overwritten by raw material sell restrictions if yield is in both groups.
Cloth is an example of this type.

EDIT:
I came up with another group.
Buy from natives
The AI tries to buy these yields from natives.

Those are well defined behavior for those groups and it's fairly strait forward to define AI behavior when adding new yields. Bonus resource group is a bogus group in comparison and needs to be changed. I just haven't figured out what it should be instead.

I warn you I can tend to go a bit crazy adding Bonuses in 2071 (Antediluvian Catacomb or Gargantuan Fossil anyone? :p:crazyeye:) Guess I like the idea of making a wide variety of very rare / exotic special sites that you can come across in exploring uncharted planets, and feel that you've discovered something unique to that place :scan::science:
Be careful when you do that. You may end up with "this is the planet with nutrients" and "this is the planet with oil". While it can be really interesting to have a divided map like that you should consider if the game is any fun if you end up on a planet without access to that resource.
 
One possible new "virtual" or non-stored Yield I've been toying with with 2071 would be Energy. You'd get a base amount of Energy for free each turn from the core buildings of your colony, and could add to the amount by constructing buildings like Fusion Reactor that give you more Energy per turn, or also by converting raw yields like Hydrocarbons to Energy through a profession. Energy could be consumed by several other city professions meaning you couldn't overtax your capacity, but would be a non-stored Yield like Hammers. I think it's already possible to implement this using XML, but I'm hesitant of impairing the already troubled AI - would the existing AI be capable of handling something like this?

Originally Posted by orlanth View Post
I warn you I can tend to go a bit crazy adding Bonuses in 2071 (Antediluvian Catacomb or Gargantuan Fossil anyone? ) Guess I like the idea of making a wide variety of very rare / exotic special sites that you can come across in exploring uncharted planets, and feel that you've discovered something unique to that place
Be careful when you do that. You may end up with "this is the planet with nutrients" and "this is the planet with oil". While it can be really interesting to have a divided map like that you should consider if the game is any fun if you end up on a planet without access to that resource.
Most of the bonuses are rare sites that add moderate amounts to the existing yields of terrains and features, but it will be wise to work out a good system of balancing yields across terrains/features ahead of implementing them. Using the graphics in my sig it'll be possible to have a wide variety of terrains if desired, but it would be good to come up with some standard ruleset for balancing yields across them to make sure things are fun & make sense. If there are a variety of terrains, I'm thinking most of them could be modestly different variants of the core terrains from the standard game (TUNDRA, MARSH, GRASS, PLAINS, DESERT, COAST, OCEAN); ie an Aquatic planet could have Silt Beds replacing Plains, which would have base yields of Plains plus some additional Silicates. I had made a start on working on an updated version of TC01's Planets mapscript awhile ago, I'll see if I can dig it up.

OTOH, it might also be fun to have a few areas which only become effectively colonizable in the late game after unlocking special terraforming or adaptation techs. :scan:
 
I think it's already possible to implement this using XML, but I'm hesitant of impairing the already troubled AI - would the existing AI be capable of handling something like this?
Maybe it will be able to handle it if energy is a raw material as well as virtual. The whole Ai thing needs further investigation as I think it's impaired regarding yields in M:C. Right now I'm working on making groups, which makes the AI/the entire game behaves the very same way as before the groups appeared. However I disagree with the content of some groups. Once I'm done the groups should be examined. The AI appears to sometime ignore the new yields. As a result they might just sell them as they haven't figured out anything else to use them for.

I haven't considered having raw materials, which are also virtual, but I will from now on.

OTOH, it might also be fun to have a few areas which only become effectively colonizable in the late game after unlocking special terraforming or adaptation techs. :scan:
RaR can transform marsh to grassland by draining. Maybe I will take a look at that and make it more generic in the sense that XML can tell which terrain can transform to which terrain. It would be even greater if it can add dependancies for doing so, like owner has invention X or plot or neighbor plot is a city with building Y. Makes sense to be able to drain marsh in medieval times if the nearby town had a mill to power the pumps.

Another idea I was thinking about recently is from Civilization: Call to Power. Underwater cities and underwater tunnels. Specially the latter can be interesting. It allows land units to move on water tiles without the aid of transports. Extremely useful if you have cities on two islands. It wouldn't be any less useful in a colonization universe where the game should handle automated wagon trains well. It goes without saying that you should invent something before you can have a submerged civilization. We could also make underwater aliens, which needs to invent something to build on land, or possibly even move on land.

Speaking of wagon trains, I wonder how to improve those. Feeder Service helps a lot, but what if you have say 5 cities in one play and 2 far away. Most of your transport will go through rough terrain to get there rather than handling local transport. We need to figure out how to make some "home zone" for automated transports. It's not top priority at the moment, but worth remembering.
 
I added YieldGroup_AI_Buy_From_Natives().

Also I noticed CvPlayerAI::AI_shouldBuyFromNative() was horribly written when you consider speed and that the AI use it all the time. The vanilla code went like this:
  1. Look up pTransport->plot()->getPlotCity() (that's two pointer lookups)
  2. check if that pointer is NULL
  3. check if bCargo is set for the yield in question
  4. check if native sell price is below 1
  5. look up pTransport->plot()->getPlotCity() again and get the owner (that's 3 pointer lookups)
  6. call getTradeYieldAmount() with the owner as argument
  7. switch case to tell if it should return true or false
Everything except #7 returns false if the check fails.

I rearranged it to start with #7. If that one fails, then return false. This is because it's instant compared to the other checks and there is no reason to look up data if that check fails.
#5 now uses the pointer found in #1 preventing the same lookup twice.
This should provide the same result a whole lot faster.

I also have my eye on #3. It looks up if bCargo is set in XML. However it looks like it provides the same as asking if the yield is virtual, except the latter is a lot faster. I wonder about just using a virtual check and assert on game start with the XML check code if that assumption is incorrect.

Basically the assumption is:
Everything before hammers has bCargo set.
Everything after hammers has bCargo unset.
Hammers also have bCargo unset.
Can this assumption break anything?

We can make the code faster in a lot of places if we can assume this. However I don't dare to just assume without confirming that the game will still work afterwards.

EDIT:
Just for the record. The new groups and how they are defined can be read here: https://github.com/Nightinggale/Medieval_Tech/blob/master/DLL_Sources/Yields.cpp (starting on line 124)
I hope this is clear enough to figure out.

EDIT:
Now the yield groups are really showing their worth in addition to being mod friendly. YieldGroup_AI_Sell_To_Europe is used by the AI to figure out which yields to sell to Europe (hence the name). With the newest commit it is also used when the AI is low on money and have to figure out what to produce in the colonies to correct this problem. Seems logical that it would go for anything it can make, which it will sell to Europe while at the same time not encourage anything it refuse to sell anyway. This even fixed the bug that the AI would sell YIELD_SHEEP and YIELD_WOO, but didn't encourage it's cities to produce those.
 
Basically the assumption is:
Everything before hammers has bCargo set.
Everything after hammers has bCargo unset.
Hammers also have bCargo unset.
Can this assumption break anything?

We can make the code faster in a lot of places if we can assume this. However I don't dare to just assume without confirming that the game will still work afterwards.
I think that should be a fine assumption, as long as we remember to keep XML set up that way with only "virtual" <bCargo>0 yields after Hammers. I forget, but I'm thinking YieldInfos.xml one of those finicky xml files where specific ordering matters a great deal for gamefonts etc..

Another idea I was thinking about recently is from Civilization: Call to Power. Underwater cities and underwater tunnels. Specially the latter can be interesting. It allows land units to move on water tiles without the aid of transports. Extremely useful if you have cities on two islands. It wouldn't be any less useful in a colonization universe where the game should handle automated wagon trains well. It goes without saying that you should invent something before you can have a submerged civilization.
Hmm that does sound cool :cool::scan::goodjob: Perhaps the Citytype feature of M:C could be reused, so the Human civs could develop a later tech enabling them to construct underwater domed cities. (another cool possibility would be a tech enabling you to develop one or two Starbases in Deep Space using a special citytype :scan:)
We could also make underwater aliens, which needs to invent something to build on land, or possibly even move on land.
Yes, sounds cool as well. The Ichthyoids and Amphibians in old 2071 currently aren't that special with no actual water terrain in game :lol: But with this they could start out with a strong foothold in the oceans of a planet, making raids on coastal settlements until either they or the humans develop techs to colonize/attack each other's home terrains :scan::king: The vanilla mechanism for placing native starts in certain terrains would have to be fixed up though, it can currently result in stuff like desert Inuits even in RaR.
 
I stopped coding for a moment, took a step back and looked at what I have made so far. The number of groups, consistency checks and such keeps on increasing and the files has become rather big. If we add #ifdef like planned and have two mods in one in those files, then everybody will get confused when reading those files. Something had to be done and I did.

I split the two files into no less than 5. One cpp and header to perform the tests, one cpp and header for MC and one header to link everything together with the rest of the code.

Now adding a new mod will be as follows
  1. Copy Yields_Medieval_Tech.cpp and Yields_Medieval_Tech.h.
  2. Give the copies appropriate names (like Yields_Colonization_2071.cpp)
  3. add the new header as an include in Yields.h.
  4. Change the #ifdef in those files to the 2071 define flag. (those #ifdef aren't added yet)
  5. Add the two new files to the VC++ project and git
This way each mod has two files of it's own to set up yields and everything in those two files are mod specific. It should now we way easier to set up yields without mixing up the mods and without getting confused about how the setup is checked.

Try to read the two source files. I think anybody capable of XML modding can figure out how to set up those files. It's not complex. At most the YieldGroup functions in the header could be an issue, but they are checked against the build() functions in the cpp meaning they can't get out of sync.

The content of BaseCheckYieldGroup::checkXML() is written by a script, which even supports having different names in C++ and XML (line YIELD_NUTRIENT). It should be fairly simple to set up manually, but if there is a need to set this up quickly with a lot of new yields, then I can run the script again if requested.

Now that I know the end result is readable and modable, I can go back to implementing the YieldGroups again. They turned out to be a bit more work than I expected, but they enforce consistent AI yield usage, which mean on top of being a mod friendly feature, it's also a bug hostile feature. This makes it worth the extra time needed.
 
Progress report.
If we ignore CvCity::doYields(), which I skipped intentionally due to complexity, then this is the status:

Complete: (as in no longer in the general code)
YIELD_SILVER
YIELD_FUR
YIELD_BARLEY
YIELD_GRAPES
YIELD_CLOTH
YIELD_COATS
YIELD_SALT
YIELD_COTTON
YIELD_LEATHER_ARMOR
YIELD_SCALE_ARMOR
YIELD_MAIL_ARMOR
YIELD_PLATE_ARMOR

Still present:
YIELD_FOOD
YIELD_GRAIN
YIELD_CATTLE
YIELD_SHEEP
YIELD_WOOL

YIELD_LUMBER
YIELD_STONE
YIELD_SPICES
YIELD_ORE
YIELD_ALE
YIELD_WINE

YIELD_TOOLS
YIELD_WEAPONS
YIELD_HORSES
YIELD_TRADE_GOODS

The red ones are related to nobles, banquets and luxury food. Rather than working hard on getting rid of them I'm considering adding #ifdef USE_NOBLE_CLASS. If I get rid of all the red yields that way I would say we could accept keeping the rest in the code. The remaining yields all have special meaning, but we should all have a pretty good idea about their role in the game. A number of the red yields are only remaining in a few locations in the code, but they are still a bit tricky to remove without hurting M:C. #ifdef can be implemented with no performance impact for M:C at all.

I just realized my comments on what the armor yield groups aren't that accurate. Basically speaking it tells the AI which yields are armors and it uses this info when building an army. The probability of the AI NOT buying an armor in Europe when it has the chance goes 1/2, 1/3, 1/4 etc meaning the further down the list of yields the armor is, the better the AI expects it to be.

The description for Check_YieldGroup_City_Billboard::build() is intentionally left vague as I couldn't do it any better. It has something to do with yields showing up next to the city name on the main map. If I get this right, if you add horses to the list, it will show horses on the city name if the city has any horses stored. I didn't really experiment with this. All I did was to rewrite the code to provide the same result for the same yields, but in a way that the specific yields are only present in Yields_Medieval_Tech.[cpp|h].

The final list of yield groups (assumed final) is here: https://github.com/Nightinggale/Medieval_Tech/blob/master/DLL_Sources/Yields_Medieval_Tech.cpp
 
Ok sounds good. I viewed those files and agree they look readable and straightforward to mod, though the details of how you implemented the whole system itself go way over my head & DLL ability :crazyeye:

For the hardcoded yields where there's a core game reason to stay individually hardcoded (eg FOOD, LUMBER, STONE, ORE, WEAPONS, HORSES, TOOLS, TRADE_GOODS), I agree it won't be a big deal to keep those standard names in XML as well if that saves work on the DLL side. It's not a problem remembering to always code XML for Nutrients as YIELD_FOOD or Firearms as YIELD_WEAPONS etc, since they have the same function. It would only cause confusion assigning new modmod yields to M:C specific ones like YIELD_SALT or YIELD_SPICES which may have specific DLL coding that modmodders won't be aware of, and that'll be solved with the group system :king: If an ifdef can inactivate hardcodes for the red yields that would also seem perfect for modmodding (am I right that those yields could then be repurposed for any new generic yield, and have the specific behaviors that result from the yieldgroups you assign them to?)

I synced a commit adding back XML for the asserted trade techs and building content and making a few more edits.. the only remaining assert is FUEDALISM which I didn't add back to civicinfos for techs, I think that's specifically Noble-related so it might be resolved through #ifdef USE_NOBLE_CLASS .

I'm not sure, but I think that Billboard thing might have to do with Native cities showing a circular icon if there's a particular Yield they're demanding (usually guns/tools/goods in the vanilla game).
 
It's not a problem remembering to always code XML for Nutrients as YIELD_FOOD or Firearms as YIELD_WEAPONS etc, since they have the same function.
Look at the file again.
// first argument is YieldTypes enum value while the second is the name in XML
checkSingleXMLType(YIELD_FOOD, "YIELD_FOOD");
All you have to do is to change the line to:
checkSingleXMLType(YIELD_FOOD, "YIELD_NUTRIENTS");
That way whenever the DLL code refers to YIELD_FOOD, it mean whatever is named YIELD_NUTRIENTS is XML. There is a similar "translator" for python, which I mentioned earlier.
For the record the compiler don't care for the number of spaces. I filled out the entire list with a script and it added the spaces for readability. The script reads the yields directly from the header file meaning it shouldn't be hard to keep the list up to date. The same script can also generate the needed list for python access.
It's also worth noting that checkSingleXMLType() doesn't actually make the connection between XML and C++. That connection is still done the vanilla way, which is to assume the first one in the enum is the first in XML and so on. I added that function to generate an assert if the enum and XML goes out of sync. The game would work just fine even if you say made a typo and called the first one YIELD_MUTRIENTS. The main reason I added it is to prevent something like YIELD_ORE getting linked to YIELD_LUMBER. While the computer doesn't care, the result ingame could be.... interesting :eek:

(am I right that those yields could then be repurposed for any new generic yield, and have the specific behaviors that result from the yieldgroups you assign them to?)
I think it's best if the hardcoded yields stays in the groups they are in right now (if any) and they shouldn't be added to any other groups. The AI could get confused. Some stuff could be done, but you have to be careful.

The idea is that you can add brand new yields to the enum and then add those yields to the groups. That way you have full control on how the AI treats them. You are also free to name them whatever you want, which is likely the same as in XML/python.

I synced a commit adding back XML for the asserted trade techs and building content and making a few more edits.. the only remaining assert is FUEDALISM which I didn't add back to civicinfos for techs, I think that's specifically Noble-related so it might be resolved through #ifdef USE_NOBLE_CLASS .
I think the best plan would be as follows:
  • Add new yield files for 2071.
  • Strip them for all unwanted yields.
  • Compile, add #ifdef whenever it encounters an error. (presumably, though each location should be checked)
  • Once it compiles we use the new DLL with 2071 and see what asserts are left.
I don't know how long it will take, but the sooner I get started, the sooner I finish. If everything goes well it should be a matter of days.
 
Ok, I stripped the M:C specific yields out of various XMLs and replaced with 2071 names in YieldInfos, also uploaded a Yields_2071.cpp with new names in BaseYieldCheckGroup , didn't edit Yields.h yet since I wasn't sure if you were finished changing it from the version a few posts back. I replaced almost all the M:C specific yieldnames for testing purposes, leaving just a few of the "virtual" ones unchanged at the end. I actually ran out of room for more 2071 yields since there are fewer in M:C than the 2071 design doc, OTOH it's probably best for design reasons to cut down the number of yields at least to begin with. I think I'll start reworking the design document to use a smaller number of yields (as always I'm open to suggestions/advice/requests .. anyone? Bueller? anyone?), but for now the replaced yields in the current commit should work well for testing.

I wasn't quite sure what do do with the armor yields yet, not having an exactly analogous mechanism planned out for 2071. I'm looking over the combat system xml entries and trying to learn how they actually work; it looks promising that much of it seems to be implemented in a modular way, but I want to be sure I'm understanding things right. Here's my take on it so far, let me know how much it agrees with actual DLL behavior or if there are other important things to keep aware of:

In professioninfos, armors are one of the yields equipped by <YieldEquipedNums> (in addition to horses and weapons) that enable a combat profession, which in turn can apply a <CombatGearType> to the unit in addition to promotions and other standard professioninfos.xml effects. Each profession can also use an <AltEquipmentType> to get an added <AltFreePromotion> . It looks like the combatgeartypes refer to an entries in basicinfos/unitcombatinfos.xml, but I'm not sure what specific effect those have. Do the new combat features like "glancing blow" and "parry" etc work by checking directly for certain unitcombatinfos tags? In vanilla each unit had only one unitcombat type (like "melee" or "cavalry"); it now looks like units can have UNITARMOR, UNITTACTIC, and UNITWEAPON as well as UNITCOMBAT and/or NONECOMBAT.

At first I thought this could be difficult to adapt for modmods but now I'm thinking it might actually be really cool and useful once we get it working in a modular way. There's lots of potential to arm units with a variety of offensive/defensive yield types like Bioweapons, Phase Shields, Plasma Cannons etc in 2071, or other weapons in other modmods. One thing to keep in mind is these are all handled through Professions. (It's lucky you made those speed improvements re professions requiring yields!) So I wasn't sure of how this could be applied to naval units, but then it occurred to me that it might be possible to let naval units themselves take combat professions, e.g Plasma Frigate, Support Vessel, etc. If that's the case, the M:C combat system may already be quite modmod friendly, and several dreadnoughts should be christened in Kailric's name :goodjob::scan:
 
I wasn't quite sure what do do with the armor yields yet, not having an exactly analogous mechanism planned out for 2071. I'm looking over the combat system xml entries and trying to learn how they actually work; it looks promising that much of it seems to be implemented in a modular way, but I want to be sure I'm understanding things right. Here's my take on it so far, let me know how much it agrees with actual DLL behavior or if there are other important things to keep aware of:

In professioninfos, armors are one of the yields equipped by <YieldEquipedNums> (in addition to horses and weapons) that enable a combat profession, which in turn can apply a <CombatGearType> to the unit in addition to promotions and other standard professioninfos.xml effects. Each profession can also use an <AltEquipmentType> to get an added <AltFreePromotion> . It looks like the combatgeartypes refer to an entries in basicinfos/unitcombatinfos.xml, but I'm not sure what specific effect those have. Do the new combat features like "glancing blow" and "parry" etc work by checking directly for certain unitcombatinfos tags? In vanilla each unit had only one unitcombat type (like "melee" or "cavalry"); it now looks like units can have UNITARMOR, UNITTACTIC, and UNITWEAPON as well as UNITCOMBAT and/or NONECOMBAT.

At first I thought this could be difficult to adapt for modmods but now I'm thinking it might actually be really cool and useful once we get it working in a modular way. There's lots of potential to arm units with a variety of offensive/defensive yield types like Bioweapons, Phase Shields, Plasma Cannons etc in 2071, or other weapons in other modmods. One thing to keep in mind is these are all handled through Professions. (It's lucky you made those speed improvements re professions requiring yields!) So I wasn't sure of how this could be applied to naval units, but then it occurred to me that it might be possible to let naval units themselves take combat professions, e.g Plasma Frigate, Support Vessel, etc. If that's the case, the M:C combat system may already be quite modmod friendly, and several dreadnoughts should be christened in Kailric's name :goodjob::scan:

Yep, its all very modular. If you don't want to use <CombatGearType> or <AltEquipmentType> then that is just fine. CombatGears uses the Civ4UnitCombatInfos and the ones used in that system are...

Code:
UNITARMOR_LEATHER
UNITARMOR_SCALE
UNITARMOR_MAIL
[B]UNITARMOR_PLATE[/B]
UNITTACTIC_PARRY
[B]UNITARMOR_SHIELD[/B]
[B]UNITWEAPON_BLUNT[/B]

The ones marked in bold are actually used in the code. Plate Armor allows for "glancing Blows" that only do half damage. Shields allow for a chance that can block all damage, this can only happen once per combat. And blunt weapons can cause Crushing Blows Vs Plate Armor. This system is far from complete and is only the beginning. And yeah, we can add new things for futuristic weapons. All we have to do is add in a Combat type in the XML and then mod in its effect in the DLL;)

EDit: Note, don't use the above combatinfos for a Unit's Combat Type such as UNITCOMBAT_MOUNTED.
 
Ok, I stripped the M:C specific yields out of various XMLs and replaced with 2071 names in YieldInfos, also uploaded a Yields_2071.cpp with new names in BaseYieldCheckGroup , didn't edit Yields.h yet since I wasn't sure if you were finished changing it from the version a few posts back.
1: You added the file in the Colonization_2071 branch (outdated source)
2: The link is to the newest version of the file on github meaning whenever somebody makes a new version of that file, the same link will point to the new version.

I wasn't quite sure what do do with the armor yields yet, not having an exactly analogous mechanism planned out for 2071.
That's easy. The system is designed to accept empty groups. In that case the function in the header should be
Code:
{
    return false;
}
Remember that the function is asking if a specific yield is part of the group. Answering false with no regard to which yield it asks for is the same as an empty group. The AI should be able to figure out to ignore armor related code in this case. In fact all groups could be empty, but then the AI would never buy or sell yields and stuff like that. Not a good setup.

Hmm actually now that I think about it, there are some cases where the AI code asserts if a yield isn't part of any of the checked groups. This is to catch if an AI is clueless on what to do with that yield. Imagine we add some plant. The player might use it for something the AI can't figure out how to do, then it is stuck on it. In that case just add it to a sell group and the AI sells whatever plants it gets. It's better than filling up the colonies with them.

At first I thought this could be difficult to adapt for modmods but now I'm thinking it might actually be really cool and useful once we get it working in a modular way. There's lots of potential to arm units with a variety of offensive/defensive yield types like Bioweapons, Phase Shields, Plasma Cannons etc in 2071, or other weapons in other modmods. One thing to keep in mind is these are all handled through Professions. (It's lucky you made those speed improvements re professions requiring yields!)
It's not like we are done adapting yet. I left the most difficult parts to be dealt with last. However now I will try to add #ifdefs and see if it results in something we can accept :)

The speed improvements to yield using professions might work a bit different from what you think based on what you wrote. Before the speed was:
constant*(number of yields)*(number of professions)

Now it's
constant*(number of yields)*(number of professions using yields)

The constant is a lot lower now. However 2/7 of the speed it gained in RaRE came from the fact that very few professions in the RaR universe use yields. If you start to add a lot of yield using professions the speed boost is less impressive. Still the RaRE measurements revealed that the AI would use 12.5% less during it's turn if all professions used yields. That's still something and in my specific test scenario that was 5 seconds.

So I wasn't sure of how this could be applied to naval units, but then it occurred to me that it might be possible to let naval units themselves take combat professions, e.g Plasma Frigate, Support Vessel, etc. If that's the case, the M:C combat system may already be quite modmod friendly, and several dreadnoughts should be christened in Kailric's name :goodjob::scan:
:eek: professions to ships???
That might be the answer to something I have been wondering about for a while. RaR has "ocean ruins", but neither AI or ships set to auto explore are interested in them. If they could somehow get scout profession or DLL says if profession == scout || professsion == ship, then it might solve itself. I have a to try that one out.

We could make a long list of names to use for ships. HMS Warrior, HMS Dreadnought, HMS Beagle, USS Enterprise, USS Nautilus, IJN Yamato and Yamal.
I think the list can quickly become rather long. In a way I'm a bit surprised at that list as I just wrote ship names I remember. It turns out I know quite a number of ships as this is just a fraction of those I know :eek:
However such XML specifics isn't really what I'm aiming for at the moment.

I committed 2071 files in the source (the right one) and define flags to pick the right one at compile time. Here is how you compile:
  1. Clone a new copy of the master branch. Location doesn't matter except it should NOT be in MODS.
  2. Start the project and clean. This will provide Makefile.settings.
  3. Edit Makefile.settings as shown below.
  4. Compile and you will get the DLL inside Colonization 2071 in MODS
Makefile.settings said:
CUSTOM_CFLAGS = -DCOLONIZATION_2071
YOURMOD=(full path whatever it is in your system)Colonization\MODS\Colonization 2071

The reason why I want them to be in the same git branch is that maintaining the same source in two branches is almost like maintaining two sources, which is precisely what the plan is to avoid. Sure we can pull changes from one source to the other, but them we will mix the XML changes. We could make an M:C branch, meaning we have master for DLL only and then two branches for XML and stuff. However I think it's less confusing to just use the master branch for M:C and allow the M:C branch to compile to 2071.

I added a project configuration called "Colonization 2071". It works precisely like Assert-fast, except the GUI knows COLONIZATION_2071 is defined. This makes it easier to work with as VC++ dims whatever is inside #ifdef if the flag isn't defined. VC++ can't figure out which flags are defined in the Makefile or Makefile.config. In other words Assert, Assert-fast and Colonization 2071 provides the precise same DLL and only Makefile.config tells which mod it's for.

Next I will start to add #ifdef to get rid of hardcoded yields. I will also clean the 2071 files to strip them down to a bare minimum of yields, making them ready for adding new ones. I don't think it would be advisable if we both add/remove yields at the same time. Please don't commit into those files until I'm done or we will end up with attending commit conflicts.
 
That might be the answer to something I have been wondering about for a while. RaR has "ocean ruins", but neither AI or ships set to auto explore are interested in them. If they could somehow get scout profession or DLL says if profession == scout || professsion == ship, then it might solve itself. I have a to try that one out.

It would be much easier to adjust UnitAI logic in DLL than trying to give professions to ships just to have them scout ship wreckages.
 
It would be much easier to adjust UnitAI logic in DLL than trying to give professions to ships just to have them scout ship wreckages.
That's what my (poor) pseudo code says. In the DLL at the place where scouts heads for ruins, the check should be for scouts and ships instead of just scouts. I will take a look at this (unless somebody else beat me to it), but first I need to finish the M:C conversion into allowing 2071. I think that's my most urgent task at the moment.
 
Back
Top Bottom