Zlatko
CIW
I move all my posts here and all answers from other members, because its easier to debate in new thread then in Quick Modding Questions, my current progress in next posts below this correspondence.
Zlatko said:I want to share my code with community and i have one question.
This code correct work and allow you to only once choose your civic from one civicoption (You can only choose once your affinity, choose wise between Harmony, Purity and Supremacy).
Solved idea from THIS post.
CvGameUtils.py:
Code:def cannotDoCivic(self,argsList): ePlayer = argsList[0] eCivic = argsList[1] pPlayer = gc.getPlayer(ePlayer) if(pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_HARMONY")) == true): if(str(gc.getInfoTypeForString("CIVIC_NO_AFFINITY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_PURITY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_SUPREMACY")) == str(eCivic)): return True elif(pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_PURITY")) == true): if(str(gc.getInfoTypeForString("CIVIC_NO_AFFINITY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_HARMONY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_SUPREMACY")) == str(eCivic)): return True elif(pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_SUPREMACY")) == true): if(str(gc.getInfoTypeForString("CIVIC_NO_AFFINITY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_HARMONY")) == str(eCivic) or str(gc.getInfoTypeForString("CIVIC_PURITY")) == str(eCivic)): return True return False
This demand,
PythonCallbackDefines.py:
QUESTIONS:Code:<Define> <DefineName>USE_CANNOT_DO_CIVIC_CALLBACK</DefineName> <iDefineIntVal>1</iDefineIntVal> </Define>
1) Where is event, function, method or whatever, which trigger when i switch to some civic ?
2) I want to change cityart when some player switch to some civic, example:
ARABIA, (Saladin) have ARTSTYLE_ARABIA,
if Saladin switch to CIVIC_HARMONY, i want to ARABIA have ARTSTYLE_HARMONY,
if switch to CIVIC_PURITY it will have ARTSTYLE_PURITY,
if switch to CIVIC_SUPREMACY it will have ARTSTYLE_SUPREMACY.
here is some code improvisation / prototype but of course its not work and give a error (and if this code successful up and running, i want to put it in place from question 1)):
Do i must change artstyle of every city from player in this case ARABIA (Saladin) or it only enough to change civilization artstyle in game.Code:def cannotDoCivic(self,argsList): ePlayer = argsList[0] eCivic = argsList[1] pPlayer = gc.getPlayer(ePlayer) if(pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_HEREDITARY_RULE")) == true): (loopCity, iter) = pPlayer.firstCity(false) while(loopCity): loopCity.setArtStyleType(0) (loopCity, iter) = pPlayer.nextCity(iter, false)
1) There is none.
2) There is no setArtStyleType in python unless you exposed it.
P.S.
If there are only 4 civics, you might as well just simply write:
Why so troublesome.Code:def cannotDoCivic(self,argsList): ePlayer = argsList[0] eCivic = argsList[1] pPlayer = gc.getPlayer(ePlayer) if pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_NO_AFFINITY")): return False return True
1) dll - start with CvPlayer::canDoCivics
2) dll only - start here or here or here or here or here or there (prepare food supply for a week)
Zlatko said:1) There is none.
2) There is no setArtStyleType in python unless you exposed it.
P.S.
If there are only 4 civics, you might as well just simply write:
Why so troublesome.Code:def cannotDoCivic(self,argsList): ePlayer = argsList[0] eCivic = argsList[1] pPlayer = gc.getPlayer(ePlayer) if pPlayer.isCivic(gc.getInfoTypeForString("CIVIC_NO_AFFINITY")): return False return True
No, i don't have only 4 civics, i have several CIVICOPTION_... and i in every CIVICOPTION_... i have several CIVIC_...
I must in C++ code expose setArtStyleType in python ?
1) dll - start with CvPlayer::canDoCivics
2) dll only - start here or here or here or here or here or there (prepare food supply for a week)
1) in CvPlayer::canDoCivics i must hardcode my idea ?
2)
I was once asked to implement 2) in RaR (colo mod, but this part of the code is the same), but due to complexity and since it wasn't actually my mod, I wasn't sure if it would even be accepted in it. Still I figured out that there are two ways to do it.
A: the DLL has a unit function the exe calls to get the art string. Edit that one to return whatever art string you want. You need getOwnerINLINE() and get the civic for that player to determine which one you have. Add more art tags to xml, which can then be used as return values. You may have to mark the screen dirty in CvPlayer::doCivic() to force the exe to ask the dll for unit art for all units again. The exe is quite good at caching data like that, which is good for performance, but it can prevent your graphical changes from being visible.
B: big hack. Alter the art in the info class. I'm not recommending it, but Age Of Discovery II use that approach when declaring revolution. Likewise you could change the info class from CvPlayer::doCivic(). However doing that would ensure your ticket to programmer hell. One issue is that it doesn't reset on load or new game, but there are several other issues as well. Changing the info classes after game start is generally not a good idea.
If you have the skill to make A, then it should be fine and releasing a standalone modcomp for it would be nice as other people could benefit from it. If you have to resort to B, then I would recommend that you stop for a moment and think if you really want this feature badly enough to violate the info class concept.
Looks like Zlatko posted before I was done writing
I must in C++ code expose setArtStyleType in python ?
C++ is way better for this than python is. If you aren't ready to make this in C++, I would say you aren't ready to make this at all. I know it's a bit harsh to say it like that, but really, it's part of the graphic drawing system. You don't want to introduce python execution speed.
Well I guess you could edit the dll to cache the art strings in CvPlayer and then set the strings from python. I would consider that a poor design though.
Zlatko,
1) didn't say that you have to hardcode things there, you just asked where was the trigger.
2) maybe check this Captured City Art mod comp for ideas on how to do it
Why me always think of some crazy ideas in modding ?
@Nightinggale
I will try to make this, something i maybe don't said, i want to change city artstyle, not units.
@isenchine
I will check.
DoC has conditional city art styles (based on majority culture instead of owner, but that can be easily changed to civics or anything else really) in the DLL, including caching (no need to waste performance every time the screen is redrawn). I ran into some pitfalls you could avoid, the source code is here. Just work your way backwards from the CvCity::getArtStyle() method.
@Nightinggale
I will try to make this, something i maybe don't said, i want to change city artstyle, not units.
Oops, didn't read your first post correctly. However cities work the same way. You most likely want to edit CvCity::getArtStyleType(). Maybe it would be best to call CvPlayer::getCityArtStyleType() and then write that new function to do precisely what you want. That way you have access to the player data rather than the city data.
Something like (pseudo code)
I think that should do it as long as you add CvCivilizationInfo::getCityStyle, which will return strings from xml. It even has check for valid strings and a fallback, which mean you don't have to fill out the xml data for all civs for this to work. If you just want it for a single one, fill it out for a single one and the rest will be unaffected.PHP:CivilizationTypes& kCiv = GC.getCivilizationInfo(); if (hasCivic(CIVIC_HARMONY) && kCiv.getCityStyle(CIVIC_HARMONY).size > 0) return kCiv.getCityStyle(CIVIC_HARMONY) else if (hasCivic(CIVIC_PURITY) && kCiv.getCityStyle(CIVIC_PURITY).size > 0) return kCiv.getCityStyle(CIVIC_PURITY) (more checks) // fallback in case nothing triggers return getArtStyleType();
This should work, at least in theory. It's quite possible that it could be written a bit better than this. I just wrote this quickly without any real checks other than how city arty style works. It's more of a concept than actual code.
EDIT
Once again somebody writes while I'm typing.
including caching (no need to waste performance every time the screen is redrawn). I ran into some pitfalls you could avoid
I thought about caching as well. However I decided to keep it simple. Maybe the best solution is to cache the city style string in CvPlayer and get CvCity to read that string. It's just a matter of a single string, which can only be changed by doCivic as the style is the same for all cities. DoC appears to have one style for each city (possibly), which mean a single style cache for each player wouldn't work. However with the option of copy pasting existing code, it might still be the way to go, even if the cache isn't the best suited for your needs.
How i can see m_iArtStyleType from CvInfos.cpp is main responsible for city art style,
because in CvCity.cpp has ArtStyleTypes CvCity::getArtStyleType() const, which return PLAYER'S .getArtStyleType() from CvPlayer.cpp
from this method ArtStyleTypes CvPlayer::getArtStyleType() const and here return m_iArtStyleType this line 'return ((ArtStyleTypes)(GC.getCivilizationInfo(getCivilizationType()).getArtStyleType()));' from CvInfos.cpp
CvInfos.cpp:
Code:int CvCivilizationInfo::getArtStyleType() const { return m_iArtStyleType; }
On begging he get value here:
CvInfos.cpp:
Code:pXML->GetChildXmlValByName(szTextVal, "ArtStyleType"); m_iArtStyleType = GC.getTypesEnum(szTextVal);
CvInfos.h
Code:[COLOR="Blue"]protected:[/COLOR] ... int m_iArtStyleType;
CvCity.cpp
Code:ArtStyleTypes CvCity::getArtStyleType() const { return GET_PLAYER(getOwnerINLINE()).getArtStyleType(); }
CvPlayer.cpp
Code:ArtStyleTypes CvPlayer::getArtStyleType() const { if (GC.getInitCore().getArtStyle(getID()) == NO_ARTSTYLE) { return ((ArtStyleTypes)(GC.getCivilizationInfo(getCivilizationType()).getArtStyleType())); } else { return GC.getInitCore().getArtStyle(getID()); } }
1) if change m_iArtStyleType in CvInfos.cpp during the game, is that affect on all cities from that player in game ?
2) I am little bit confused, i already asked for trigger when and where player change CIVIC in .cpp ? I must in the moment when player switch to another civic, then i must change m_iArtStyleType. And in that part of code i can implement @Nightinggale pseudo code.
3) Player and civilization get ArtStyleType from XML, i must change that ArtStyleType, it same like when you make map in world builder and change artstyle for players or change name etc, example:
changed to HARMONYCode:BeginPlayer Team=12 LeaderType=LEADER_MANSA_MUSA LeaderName=TXT_KEY_LEADER_MANSA_MUSA CivDesc=TXT_KEY_CIV_MALI_DESC CivShortDesc=TXT_KEY_CIV_MALI_SHORT_DESC CivAdjective=TXT_KEY_CIV_MALI_ADJECTIVE FlagDecal=Art/Interface/TeamColor/FlagDECAL_Mask.dds WhiteFlag=0 CivType=CIVILIZATION_MALI Color=PLAYERCOLOR_PEACH [B][COLOR="Red"]ArtStyle=ARTSTYLE_AFRICA[/COLOR][/B] PlayableCiv=1 MinorNationStatus=0 StartingGold=0 StartingX=85, StartingY=51 StateReligion= StartingEra=ERA_ANCIENT RandomStartLocation=false CivicOption=CIVICOPTION_GOVERNMENT, Civic=CIVIC_DESPOTISM CivicOption=CIVICOPTION_LEGAL, Civic=CIVIC_BARBARISM CivicOption=CIVICOPTION_LABOR, Civic=CIVIC_TRIBALISM CivicOption=CIVICOPTION_ECONOMY, Civic=CIVIC_DECENTRALIZATION CivicOption=CIVICOPTION_RELIGION, Civic=CIVIC_PAGANISM CivicOption=CIVICOPTION_POLITICAL_PARTY, Civic=CIVIC_NO_POLITICAL_PARTY Handicap=HANDICAP_NOBLE EndPlayer
and Mansa Musa of Mali will now have ARTSTYLE_HARMONY instead ARTSTYLE_AFRICA, and i must change that variable 'ArtStyle=' in the moment during player switch to another civic, somewhere in source code.Code:BeginPlayer Team=12 LeaderType=LEADER_MANSA_MUSA LeaderName=TXT_KEY_LEADER_MANSA_MUSA CivDesc=TXT_KEY_CIV_MALI_DESC CivShortDesc=TXT_KEY_CIV_MALI_SHORT_DESC CivAdjective=TXT_KEY_CIV_MALI_ADJECTIVE FlagDecal=Art/Interface/TeamColor/FlagDECAL_Mask.dds WhiteFlag=0 CivType=CIVILIZATION_MALI Color=PLAYERCOLOR_PEACH [B][COLOR="Red"]ArtStyle=ARTSTYLE_HARMONY[/COLOR][/B] PlayableCiv=1 MinorNationStatus=0 StartingGold=0 StartingX=85, StartingY=51 StateReligion= StartingEra=ERA_ANCIENT RandomStartLocation=false CivicOption=CIVICOPTION_GOVERNMENT, Civic=CIVIC_DESPOTISM CivicOption=CIVICOPTION_LEGAL, Civic=CIVIC_BARBARISM CivicOption=CIVICOPTION_LABOR, Civic=CIVIC_TRIBALISM CivicOption=CIVICOPTION_ECONOMY, Civic=CIVIC_DECENTRALIZATION CivicOption=CIVICOPTION_RELIGION, Civic=CIVIC_PAGANISM CivicOption=CIVICOPTION_POLITICAL_PARTY, Civic=CIVIC_NO_POLITICAL_PARTY Handicap=HANDICAP_NOBLE EndPlayer
I make what i want, but its work on way on which i don't want to work. And of course this is just prototype version. Civilization get new city art when player switch to any civic (that is for now), but this new city art stay for that civilization, for example:
- I play with CHINA, and CHINA have ASIAN city style, when i switch to any civic, CHINA get ARABIAN city style, if i return to main menu and again start some new game with CHINA, CHINA have ARABIAN city style, instead of ASIAN.
- If i save game when CHINA have ASIAN city style, and change my civic, and CHINA get ARABIAN city style, and i go to load game, CHINA now have ARABIAN city style instead of ASIAN city style.
- CHINA only again get their default city style (ASIAN), if i exit from my mod, and load my mod again.
NEW CODE
CvPlayer.cpp:
Code:void CvPlayer::setCivics(CivicOptionTypes eIndex, CivicTypes eNewValue) { CvWString szBuffer; CivicTypes eOldCivic; int iI; FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)"); FAssertMsg(eIndex < GC.getNumCivicOptionInfos(), "eIndex is expected to be within maximum bounds (invalid Index)"); FAssertMsg(eNewValue >= 0, "eNewValue is expected to be non-negative (invalid Index)"); FAssertMsg(eNewValue < GC.getNumCivicInfos(), "eNewValue is expected to be within maximum bounds (invalid Index)"); eOldCivic = getCivics(eIndex); if (eOldCivic != eNewValue) { m_paeCivics[eIndex] = eNewValue; if (eOldCivic != NO_CIVIC) { processCivics(eOldCivic, -1); } if (getCivics(eIndex) != NO_CIVIC) { processCivics(getCivics(eIndex), 1); } GC.getGameINLINE().updateSecretaryGeneral(); GC.getGameINLINE().AI_makeAssignWorkDirty(); if (GC.getGameINLINE().isFinalInitialized()) { if (gDLL->isDiplomacy() && (gDLL->getDiplomacyPlayer() == getID())) { gDLL->updateDiplomacyAttitude(true); } /************************************************************************************************/ /* REVOLUTION_MOD 04/28/08 jdog5000 */ /* */ /* */ /************************************************************************************************/ /* if (!isBarbarian()) */ // Silence announcement for civs that are not alive, ie rebel civs who may not be born // and also for minor civs if (!isBarbarian() && !isMinorCiv() && isAlive()) /************************************************************************************************/ /* REVOLUTION_MOD END */ /************************************************************************************************/ { if (getCivics(eIndex) != NO_CIVIC) { if (getCivics(eIndex) != GC.getCivilizationInfo(getCivilizationType()).getCivilizationInitialCivics(eIndex)) { for (iI = 0; iI < MAX_PLAYERS; iI++) { if (GET_PLAYER((PlayerTypes)iI).isAlive()) { if (GET_TEAM(getTeam()).isHasMet(GET_PLAYER((PlayerTypes)iI).getTeam())) { szBuffer = gDLL->getText("TXT_KEY_MISC_PLAYER_ADOPTED_CIVIC", getNameKey(), GC.getCivicInfo(getCivics(eIndex)).getTextKeyWide()); gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_CIVIC_ADOPT", MESSAGE_TYPE_MAJOR_EVENT); } } } szBuffer = gDLL->getText("TXT_KEY_MISC_PLAYER_ADOPTED_CIVIC", getNameKey(), GC.getCivicInfo(getCivics(eIndex)).getTextKeyWide()); GC.getGameINLINE().addReplayMessage(REPLAY_MESSAGE_MAJOR_EVENT, getID(), szBuffer); } [COLOR="SeaGreen"]// < ZLATKO RECONSTRUCTION START > EXPERIMENT[/COLOR] [COLOR="Red"]GC.getCivilizationInfo(getCivilizationType()).setArtStyleType(2);[/COLOR] [COLOR="SeaGreen"]// < ZLATKO RECONSTRUCTION END >[/COLOR] } } } /************************************************************************************************/ /* BETTER_BTS_AI_MOD 09/03/09 poyuzhe & jdog5000 */ /* */ /* Efficiency */ /************************************************************************************************/ // From Sanguo Mod Performance, ie the CAR Mod // Attitude cache for (int iI = 0; iI < MAX_PLAYERS; iI++) { GET_PLAYER(getID()).AI_invalidateAttitudeCache((PlayerTypes)iI); GET_PLAYER((PlayerTypes)iI).AI_invalidateAttitudeCache(getID()); } /************************************************************************************************/ /* BETTER_BTS_AI_MOD END */ /************************************************************************************************/ } }
CvInfos.h:
Code:class CvArtInfoCivilization; class CvCivilizationInfo : public CvInfoBase { //---------------------------------------PUBLIC INTERFACE--------------------------------- public: .... [COLOR="SeaGreen"]// < ZLATKO RECONSTRUCTION START > EXPERIMENT[/COLOR] [COLOR="Red"]void setArtStyleType(int m_iArtStyleType);[/COLOR] [COLOR="SeaGreen"]// < ZLATKO RECONSTRUCTION END >[/COLOR] .... };
CvInfos.cpp:
Code:// < ZLATKO RECONSTRUCTION START > EXPERIMENT void CvCivilizationInfo::setArtStyleType(int m_iArtStyleType) { this->m_iArtStyleType = m_iArtStyleType; } // < ZLATKO RECONSTRUCTION END >
What is it with me and posting together with other people today? Now it's the 3rd time in one day in the same thread
- If i save game when CHINA have ASIAN city style, and change my civic, and CHINA get ARABIAN city style, and i go to load game, CHINA now have ARABIAN city style instead of ASIAN city style.
Sounds like you fail to save the variable. YOu need to add the new variable to CvPlayer::read() and write(). Order matters and you will break old savegames, unless you write some backward compatibility code using uiFlag.
Code:GC.getCivilizationInfo(getCivilizationType()).setArtStyleType(2);
I would recommend using an enum if you want to hardcode numbers into the DLL and XML values if you want it to be modder friendly. Using numbers like 2 will not only make the code unreadable, it will also haunt you later on if you need to change something.