Ethnic Buildings Mod

Asaf

Sleep Deprived
Joined
Mar 22, 2010
Messages
1,326
===============================
= Ethnic Buildings by Asaf (version 0.1) =
===============================

Download here

This Mod component enables a modder to have different art for the same building for different civilizations, the same way units art works in BTS.

Building art info defined that way is displayed at the following places:
- On the map view - as a 3D model in the city (3D model)
- Inside the city screen, as a building production order button (button image)
- Inside the city screen, when the is building currently in queue (3D model)
- On the map in the city bar, when the building is currently being built (button image)
- On the popup where the player can select the next city production (button image)
- On the minimized production popup (if used) (button image)

This art is not used in the civilopedia (since it is not connected to a specific player).
Other places which are not in Vanilla BTS (such as in BUG) are not defined here, but can be easily modded.

All the changes I made (C++, Python and XML files) are marked with an 'Ethnic Buildings' comment.

Modders how-to:

XML
Spoiler :

A new type info was added: BuildingArtStyleTypeInfo.
This type info connects civilizations to the BuildingArtInfo's relevant for them.

In Civ4CivilizationInfos, a new tag was added under CivilizationInfo: <BuildingArtStyleType>.
Its value must be defined in the new file Civ4BuildingArtStyleTypeInfos.xml.
This tag may not appear, and in that case the art used by the building is the same as was used before (ArtDefineTag in BuildingInfo).
If it does appear, it should appear after <UnitArtStyleType>.

For example:

Civ4CivilizationInfos.xml:
PHP:
		<CivilizationInfo>
			<Type>CIVILIZATION_AMERICA</Type>
			...
			<UnitArtStyleType>UNIT_ARTSTYLE_EUROPEAN</UnitArtStyleType>
			<BuildingArtStyleType>BUILDING_ARTSTYLE_AMERICA</BuildingArtStyleType>
			<bPlayable>1</bPlayable>
			...
Civ4BuildingArtStyleTypeInfos.xml:
PHP:
<Civ4BuildingArtStyleTypeInfos xmlns="x-schema:CIV4CivilizationsSchema.xml">
  <BuildingArtStyleTypeInfos>
    <BuildingArtStyleTypeInfo>
      <Type>BUILDING_ARTSTYLE_AMERICA</Type>
      <StyleBuildings>
        <StyleBuilding>
          <BuildingType>BUILDING_BARRACKS</BuildingType>
          <BuildingMeshGroup>
            <EarlyArtDefineTag>ART_DEF_BUILDING_BARRACKS_AMERICAN</EarlyArtDefineTag>
            <LateArtDefineTag>ART_DEF_BUILDING_BARRACKS_AMERICAN</LateArtDefineTag>
            <MiddleArtDefineTag>ART_DEF_BUILDING_BARRACKS_AMERICAN_MODERN</MiddleArtDefineTag>
          </BuildingMeshGroup>
        </StyleBuilding>
      </StyleBuildings>
    </BuildingArtStyleTypeInfo>
	...

Note that there can only be one mesh group (unlike unit art styles), and here too you can have different art for different eras (same as with units).

Of course, some or all eras may have the same art, but if you define a StyleBuilding, you must define a single BuildingMeshGroup in it with all 3 possible eras defined.

In this example, ART_DEF_BUILDING_BARRACKS_AMERICAN and ART_DEF_BUILDING_BARRACKS_AMERICAN_MODERN should be defined in CIV4ArtDefines_Building.xml, each as a BuildingArtInfo of its own.

Appropriate changes were made to the civilization scheme (make sure you merge it to your Mod).


Python
Spoiler :

In order for the correct 3D model to be displayed in the city screen, I used a minor 'hack':

The drawing of this model is done by calling addBuildingGraphicGFC(), which in turn calls the DLL function CvGame::getBuildingArtInfo(). Since in CvGame::getBuildingArtInfo() the player information does not exist, then before calling addBuildingGraphicGFC() the Python code calls the new function CyGame().setBuildingModelCity() and passes the city ID and the owner ID.
This enables the DLL to return the correct art for the player.
When merging the Python code to your Mod (or with BUG or any other Mod) make sure to leave these lines (see updatePlotListButtons() in CvMainInterface.py).

New exported functions to python:

void CyGame.setBuildingModelCity(int iCityId, int /*PlayerTypes*/ eOwner) - Described above.
int CvCivilizationInfo.getUnitArtStyleType() - For some reason was not defined.
int CvCivilizationInfo.getBuildingArtStyleType() - Returns the ID of the building art style type defined for this civilization (-1 for NONE)
string CyPlayer.getBuildingButton(int eBuilding) - Returns the building button for this player.

Credits:
========
DannyDaemonic - the fast Makefile (1.0). Downloaded from: http://forums.civfanatics.com/showthread.php?t=370861
j_mie6 - For the idea (requested this Mod)


EDIT: You are more than welcome to use this mod component in your own mods, but if you do - please let me know.
 
So basically this just shows the ethnic improvement art (say from a mod like Cultural Citystyles) in the Civilopedia and City Screen?

I was wondering if this could be altered to make wonders ethnic as well? For instance could there be an ethnic wonder for the Great Wall, like the Romans would get Hadrian's wall instead or is that way too complex to do?
 
So basically this just shows the ethnic improvement art (say from a mod like Cultural Citystyles) in the Civilopedia and City Screen?

I was wondering if this could be altered to make wonders ethnic as well? For instance could there be an ethnic wonder for the Great Wall, like the Romans would get Hadrian's wall instead or is that way too complex to do?

City screen - yes, civilopedia - no, although I can probably change it so that when watching the civilopedia in game (and there's an active player) it will display the player's art style. Not sure if that's a good thing though.
And not improvements (as in tile improvements - farm, mine, etc.) but buildings built in the city.

Wonders are basically buildings for which the building class has iMaxGlobalInstances=1, so yes, they will be ethnic as well.

The movies, however, are not included in the 'ethnic art'. I guess it's doable, but I haven't seen many movie makers for mods, so I'm not sure if it's needed.

Specifically for the Great Wall, the art of displaying the wall around the cultural borders is not included in the ethnic buildings since it's not part of the art assets (as far as I know), and not part of the BuildingArtInfo.
 
Great work I'm sure that many people (including myself), will be very happy to see this!

I will have a play on friday! :D
 
yer but the other way is very complicated and this would be so much better for new modders
 
The sad part here: That was already possible in standard BtS :(.

Oh. :blush:
How? (Probably something that has to do with LSystem, which I could never understand)

The good part here: That implementation is definitely better and should have been done in that way by default :).

Yey! :cool:

Maybe I should open a thread for every mod comp I intend to make before I make it...
 
Oh. :blush:
How? (Probably something that has to do with LSystem, which I could never understand)

Yup, that. I don't really understand it too.

Yey! :cool:

Maybe I should open a thread for every mod comp I intend to make before I make it...

:lol:
If you make more, then maybe one big thread for all is better, then you also have your own "discussion" ground, that's maybe easier :D.
 
Yup, that. I don't really understand it too.

If it's that complicated, maybe this mod will be useful after all :whew:
 
oh it is! You have given alot of new modders a great new asset previously too scary for them to handle! :D
 
ummm I just downloaded complete edition, new to the game, can anyone tell me how to install mods? I download the file, and unzip it where??
 
unzip to your documents and drag the intire file to computer/program files/2k games/civilization complete/beyond the sword/mods or somethign simmilar

(you only have to past in documents if you are on vista)
 
What about these files? Do they go to in the Custom Assests? The Ethnic buildings are more just graphics than gameplay enhancers right? So if i unzip to mods, wont i have to load it every time?
 
This mod doesn't have any graphics of its own. It's just a mod component to make it easier for other modders to assign specific building art to specific civilizations.

Unless you have art files of your own (or somebody else's) that you want to use, you really don't need this mod.
 
Interesting... I would like to switch to this for my Magyar Mod, but there are some cons. But I have some questions.

1.) You said that this enables art for different eras which is misleading. Eras would be like ERA_INDUSTRIAL, but I see your point. Nevertheless, I would need eras in the actual sense as for some buildings I have art allowing me to flavor buildings more precisely. I have no clue about python modding, but I believe that the definitions for the eras should already be available as the game already uses them. For the XMLs, it should be rather unimportant what kind of eras you use. So, could you update this to use eras in the actual sense? Only then, I would use this.

2.) Does this support modular modding? I assume so.

3.) Is it multiplayer save?

4.) Would it be possible to flavour the citysets, too? I mean, not only those buildings that the player wants to build at some point, but also those generic houses? Even if not, This file would simplify my mod and merging it, so I could live without it.

So, if you could update this so that point 1 to 3 are fulfilled, I'd gladly use this...
 
1.) You said that this enables art for different eras which is misleading. Eras would be like ERA_INDUSTRIAL, but I see your point. Nevertheless, I would need eras in the actual sense as for some buildings I have art allowing me to flavor buildings more precisely. I have no clue about python modding, but I believe that the definitions for the eras should already be available as the game already uses them. For the XMLs, it should be rather unimportant what kind of eras you use. So, could you update this to use eras in the actual sense? Only then, I would use this.
True, it might be a bit misleading, but it works the same as with the unit art style per era (you have early, middle, and late, which consist of 25%, 25% and 50% of the eras, if I'm not mistaken).
It could be done, but unfortunately I simply don't have time to mod, and will probably won't have time in the near future. So if someone else wants to do it - you're more than welcome to.

2.) Does this support modular modding? I assume so.
I guess so, but I've never tried it like that myself.

3.) Is it multiplayer safe?
It should be. I don't see a reason it won't be. But again, never tested.

4.) Would it be possible to flavour the citysets, too? I mean, not only those buildings that the player wants to build at some point, but also those generic houses? Even if not, This file would simplify my mod and merging it, so I could live without it.
Oh, I don't really know. I'm guessing it's doable, but I have never looked at this code so I can't say for sure if and how easy it would be.

Sorry I couldn't be more helpful...
 
I see... I might try to get help with this from other users. Sounds like that would be okay to you.
 
So I've started to work on this. I think I successfully merged your package with WoC Lite, now I'm working on the era thing. Basically, I replace all the early, middle and late functions / calls with ancient, classical, medieval, renaissance, industrial, modern and future counterparts. It basically works, but there are two problems. A basic problem is that the game crashes if there is an invalid artdef referenced in the buildingartstyletype file, even without telling the user why. It would be the best if we would get a parse error if such things happen or at least if we simply don't show any building. Hints? These are the errors I got when the game crashed and debug mode was enabled:
Spoiler :
Assert Failed

File: CvArtFileMgr.cpp
Line: 175
Expression: false
Message: get##name##ArtInfo: ART_DEF_BUILDING_HUNG_VEGVARE was not found



Assert Failed

File: CvArtFileMgr.cpp
Line: 175
Expression: false
Message: get##name##ArtInfo: ERROR was not found


The second problem is that the modern and the future eras don't work properly. I assume it is because of the following code (CvInfos.cpp):
Spoiler :
if ((eEra >= 6) && !CvString(getFutureArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getFutureArtDefineTag(eStyle));
}
else if ((eEra == 5) && !CvString(getModernArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getModernArtDefineTag(eStyle));
}
else if ((eEra == 4) && !CvString(getIndustrialArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getIndustrialArtDefineTag(eStyle));
}
else if ((eEra == 3) && !CvString(getRenaissanceArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getRenaissanceArtDefineTag(eStyle));
}
else if ((eEra == 2) && !CvString(getMedievalArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getMedievalArtDefineTag(eStyle));
}
else if ((eEra == 1) && !CvString(getClassicalArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getClassicalArtDefineTag(eStyle));
}
else if (!CvString(getAncientArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getAncientArtDefineTag(eStyle));
}

which replaced
Spoiler :
if ((eEra > GC.getNumEraInfos() / 2) && !CvString(getLateArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getLateArtDefineTag(eStyle));
}
else if ((eEra > GC.getNumEraInfos() / 4) && !CvString(getMiddleArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getMiddleArtDefineTag(eStyle));
}
else if (!CvString(getEarlyArtDefineTag(eStyle)).empty())
{
return ARTFILEMGR.getBuildingArtInfo(getEarlyArtDefineTag(eStyle));
}

I was assuming GC.getNumEraInfos() returns 7 for default BtS games as there are 7 eras. Dividing it by 2 returns 3.5, thus 4, 5 and 6 make the expression true. Late therefor stood for industrial, modern and future. Dividing it by 4 makes 1,75 and as 4, 5 and 6 are already out, 2 and 3 make the expression true. Thus, Medieval and Renaissance make up what was middle before or is for units. 0 and 1 thus stand for ancient and classical. Am I right? I have used fixed numbers to get this work for all the eras (I used >= 6 to have the code keep working if someone hacked the eras). Did I make any msitake?
 
Seems like I was wrong and the selection of the building art in-deed works as expected. My problem was only that in workbuilder I had choosen the wrong technologies, so the future era was never actually reached. After I added a breakpoint, I noticed that the function I cited from was never called as I had expected it. After selecting a few techs more the function got called and everything worked as expected. Now I will try to find a way to avoid a crash if an artdef is invalid or at least tell the user about the reasons. Besides of this, the new modcomp is functional and if anyone cares, I could upload it already so you can test it...

EDIT: I believe I found an acceptable solution using this code:
Spoiler :
CvArtInfoBuilding* dummy = NULL;

if (eStyle != NO_BUILDING_ARTSTYLE)
{
if ((eEra >= 6) && !CvString(getFutureArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getFutureArtDefineTag(eStyle));
}
else if ((eEra == 5) && !CvString(getModernArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getModernArtDefineTag(eStyle));
}
else if ((eEra == 4) && !CvString(getIndustrialArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getIndustrialArtDefineTag(eStyle));
}
else if ((eEra == 3) && !CvString(getRenaissanceArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getRenaissanceArtDefineTag(eStyle));
}
else if ((eEra == 2) && !CvString(getMedievalArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getMedievalArtDefineTag(eStyle));
}
else if ((eEra == 1) && !CvString(getClassicalArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getClassicalArtDefineTag(eStyle));
}
else if (!CvString(getAncientArtDefineTag(eStyle)).empty())
{
dummy = ARTFILEMGR.getBuildingArtInfo(getAncientArtDefineTag(eStyle));
}
if (dummy!=NULL)
return dummy;
}

return ARTFILEMGR.getBuildingArtInfo(getArtDefineTag());
The ARTFILEMGR.getBuildingArtInfo(getXYZArtDefineTag(eStyle)); will return NULL if the artdef is invalid, so we'll save the return value in dummy and then evaluate it. If it isn't NULL, everything was okay and we can leave the function returning dummy's value, otherwise we will stay in the function. Next and last thing the function will try is retrieving the buildings default artdef and return that. If there is no default artdef, I think the game would have thrown an error at us at mod loading phase, although I'm not too sure about that. At least, this should be a far more obvious xml mistake then a typo in the eras artdefs. To summarize it up, the game now should fall back to the default artdef if no valid artdef is available for the desired era. This ways, the modder might not even notice that there is an error, but that's still better than a crash. Also, if I'm not mistaken, it should be possible to just not give an artdef for certain eras that shall use the default art. Haven't tried what would have happened with asafs original dll and what happens now in this case though. Let me know if you guys see any problem with this code.
 
In C++, the result of dividing an int is always rounded down - the non-integer part is truncated. So when you divide 7 by 2 you get 3, not 4.

As for the crush - I think that's true for all the art definitions in the game, even for the original DLL (unit art style etc.).
If you want to solve this, you could probably assign a default art style when the art style is invalid.

If it's working - sure! post your mod comp, and add a link here.
 
Top Bottom