Quick Modding Questions Thread

How do Settler costs work? Looking into the unit XML they have iCost set to 0, but clearly they do not cost nothing. I checked CvPlayer::getProductionNeeded and there does not seem to be any custom code to handle settler cost. Where can I change it?
 
Changed in BTS.
Settlers are "isFound()" in the C++

in CvPlayer::Init you'll find this :

setUnitExtraCost((UnitClassTypes)iI, getNewCityProductionValue());



Code:
int CvPlayer::getNewCityProductionValue() const
{
    int iValue = 0;
    for (int iJ = 0; iJ < GC.getNumBuildingClassInfos(); iJ++)
    {
        BuildingTypes eBuilding = ((BuildingTypes)(GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iJ)));


        if (NO_BUILDING != eBuilding)
        {
            if (GC.getBuildingInfo(eBuilding).getFreeStartEra() != NO_ERA)
            {
                if (GC.getGameINLINE().getStartEra() >= GC.getBuildingInfo(eBuilding).getFreeStartEra())
                {
                    iValue += (100 * getProductionNeeded(eBuilding)) / std::max(1, 100 + getProductionModifier(eBuilding));
                }
            }
        }
    }


    iValue *= 100 + GC.getDefineINT("NEW_CITY_BUILDING_VALUE_MODIFIER");
    iValue /= 100;


    iValue += (GC.getDefineINT("ADVANCED_START_CITY_COST") * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getGrowthPercent()) / 100;


    int iPopulation = GC.getDefineINT("INITIAL_CITY_POPULATION") + GC.getEraInfo(GC.getGameINLINE().getStartEra()).getFreePopulation();
    for (int i = 1; i <= iPopulation; ++i)
    {
        iValue += (getGrowthThreshold(i) * GC.getDefineINT("ADVANCED_START_POPULATION_COST")) / 100;
    }


    return iValue;
}


This is to balance the cost of Settlers for Eras Start (medieval onwards) where you have a starting buildings, factor in the traits etc. in those cases.
If you only do Ancient start you can bin all this and write your number ;)

For the little story, apparently this was added in the last days of production of BTS, untested by the beta-tester, as a results of top MP players destroying a Firaxis team in late era start by making super fast super numerous cities,
Hence Firaxis finding a way to make cities very expensive in those scenarios.
 
It seems that firaxis modified the boost python c++ source code. If you compile the boost python dll from the boost 1.32 source code and put that into the beyond the sword folder the game stops working.

So they must have changed something, does anyone know if they released the code for their fork of boost somewhere?
 
To complement my answer to Leoreth on the Settler cost,
Here is how I (more easily) circumvented the issue.
Via an option and Via a Constant that I declared in XML


in...
int CvPlayer::getProductionNeeded(UnitTypes eUnit) const

Code:
........


    if (!GC.getGameINLINE().isOption(GAMEOPTION_WARLORD_SETTLER_COST))//2.32q
    {   
        iProductionNeeded += getUnitExtraCost(eUnitClass);//This is the default line
    }
    else if (GC.getUnitInfo(eUnit).isFound())
    {
        int iFixedSettlerCost;
        iFixedSettlerCost = GC.getDefineINT("BTG_WARLORD_SETTLER_COST" ) * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
        iProductionNeeded += iFixedSettlerCost / 100;
    }
 
How is determined the sequence of animations during a fight ?
When two units are fighting, they are each hitting the other in a seemingly random order, and I would like to mod the number of hit they give before the battle end.
 
@Akka
this is quite complicated. its a code that lies in the unit cpp under resolvecombat code.
need kits of background knowledge.
I have some knowledge of coding, so that shouldn't be too much of a problem ^^ (and in fact, thanks, I didn't realize that so much of the code was simply freely available in CvGameCoreDLL :eek: )

Though after having a look at resolveCombat, I only found logic for calculating the fight, so I think I expressed myself in a rather confusing way.
To give more context : I don't want to change the mechanisms under the hood, I just want to change the combat ANIMATIONS. Specifically, I'd like to make it that combat only have a single animated attack before resolution, rather than the drawn-out echange of blows in the regular game.

Edit : after digging around, it seems that the function planBattle is the one setting up the "script" of animated fighting, but despite all the changes I tried, nothing has had any impact. I guess they aren't directly used by the game, and I'll have to compile them. Time to fire up VS.
 
Last edited:
I was under the impression the animations had something to do with how hits themselves are resolved, but perhaps that's incorrect.
 
Changed in BTS.
Settlers are "isFound()" in the C++

in CvPlayer::Init you'll find this :

setUnitExtraCost((UnitClassTypes)iI, getNewCityProductionValue());



Code:
int CvPlayer::getNewCityProductionValue() const
{
    int iValue = 0;
    for (int iJ = 0; iJ < GC.getNumBuildingClassInfos(); iJ++)
    {
        BuildingTypes eBuilding = ((BuildingTypes)(GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iJ)));


        if (NO_BUILDING != eBuilding)
        {
            if (GC.getBuildingInfo(eBuilding).getFreeStartEra() != NO_ERA)
            {
                if (GC.getGameINLINE().getStartEra() >= GC.getBuildingInfo(eBuilding).getFreeStartEra())
                {
                    iValue += (100 * getProductionNeeded(eBuilding)) / std::max(1, 100 + getProductionModifier(eBuilding));
                }
            }
        }
    }


    iValue *= 100 + GC.getDefineINT("NEW_CITY_BUILDING_VALUE_MODIFIER");
    iValue /= 100;


    iValue += (GC.getDefineINT("ADVANCED_START_CITY_COST") * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getGrowthPercent()) / 100;


    int iPopulation = GC.getDefineINT("INITIAL_CITY_POPULATION") + GC.getEraInfo(GC.getGameINLINE().getStartEra()).getFreePopulation();
    for (int i = 1; i <= iPopulation; ++i)
    {
        iValue += (getGrowthThreshold(i) * GC.getDefineINT("ADVANCED_START_POPULATION_COST")) / 100;
    }


    return iValue;
}


This is to balance the cost of Settlers for Eras Start (medieval onwards) where you have a starting buildings, factor in the traits etc. in those cases.
If you only do Ancient start you can bin all this and write your number ;)

For the little story, apparently this was added in the last days of production of BTS, untested by the beta-tester, as a results of top MP players destroying a Firaxis team in late era start by making super fast super numerous cities,
Hence Firaxis finding a way to make cities very expensive in those scenarios.

To complement my answer to Leoreth on the Settler cost,
Here is how I (more easily) circumvented the issue.
Via an option and Via a Constant that I declared in XML


in...
int CvPlayer::getProductionNeeded(UnitTypes eUnit) const

Code:
........


    if (!GC.getGameINLINE().isOption(GAMEOPTION_WARLORD_SETTLER_COST))//2.32q
    {  
        iProductionNeeded += getUnitExtraCost(eUnitClass);//This is the default line
    }
    else if (GC.getUnitInfo(eUnit).isFound())
    {
        int iFixedSettlerCost;
        iFixedSettlerCost = GC.getDefineINT("BTG_WARLORD_SETTLER_COST" ) * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
        iProductionNeeded += iFixedSettlerCost / 100;
    }
Thanks! That's some funny additional context.

I think what they are doing makes a lot of sense, part of the reason I am asking is that I actually do want to make settler cost scale by era. For my mod I actually already changed the starting buildings etc. to depend not on "starting era" but on current era because civilizations can start in any era, even if the game started in the ancient era, so maybe I should also adapt the code here to work like this and see if it achieves what I am looking for.
 
I was under the impression the animations had something to do with how hits themselves are resolved, but perhaps that's incorrect.
From what I've gathered in the code, the result of the fight is calculated quickly, and then the animations are scripted in a mostly random way, but with the results taken into account to ensure consistency (for example, the unit losing the fight must be the last losing a character in the animation).
IMO, it's pointlessly convoluted for an end result that is actually annoying (hence my desire to mod it so that a fight has only one animation).
 
Have a nice day. I need an advice. I have new terrains and fatures. I would like to take them into account in new promotions. I use it for that
Code:
            <FeatureDoubleMoves>
                <FeatureDoubleMove>
                    <FeatureType>FEATURE_MYSTPLACE</FeatureType>
                    <bFeatureDoubleMove>1</bFeatureDoubleMove>
                </FeatureDoubleMove>
                <FeatureDoubleMove>
                    <FeatureType>FEATURE_VRES</FeatureType>
                    <bFeatureDoubleMove>1</bFeatureDoubleMove>
                </FeatureDoubleMove>
            </FeatureDoubleMoves>
and <TerrainDoubleMoves> etc

Unfortunately, this entry has no effect. Is there something I missed? Does anyone have experience with this?
 
Last edited:
What's the easiest way to make popup pop for ALL players ?
Click on a button/slider/and it makes the popup menu appear for everyone.

I'm thinking it should be a straightforward 1 line thing, before I jump into supr convoluted things



For what it's worth I :
1) Have a button on the mainInterface that calls my (dedicated python file) with my popup screen
Code:
        elif(inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED and inputClass.getFunctionName() == "MapPreviewButton"):
            CvMapPreviewScreen.CvMapPreviewScreen().showMapReviewPopup()

2) I've tried using popinfo function but it doesn't work. I was under the impression that "popupInfo.addPopup(iPlayer)" would let me directly pick the player to which the popup opens but it's always the activePlayer that has the popup
Code:
elif(inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED and inputClass.getFunctionName() == "MapPreviewButton"):
            #2.37i
            popupInfo = CyPopupInfo()
            popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
            popupInfo.setText(u"showMapPreviewScreen")
            #popupInfo.addPopup(iPlayer)
            popupInfo.addPopup(0)
            popupInfo.addPopup(1)

3) I don't think there is anything in the screen/popup that is relevant (maybe that's where my knowledge is lacking). For illustration, here are the first and last line of the main/only function
Code:
def showMapReviewPopup(self):
      
        popup = PyPopup.PyPopup(-1, EventContextTypes.NO_EVENTCONTEXT, True)
      
      
      
        .......
      
      
      
      
      
        popup.launch(True, PopupStates.POPUPSTATE_IMMEDIATE)#



EDIT : actually I feel like .addpopup LIMITS the popup to case where the 'int' provided is equal to the activeplayer number only
 
Alternaltively - How do you make a screen open on several player's screen at the same time ? I might have to rebuild my screen as a screen anyways !
 
Is there a way to make the ships move like the troops as in the attached image? Thank you
 

Attachments

  • Screenshot 2024-01-27 085918.jpg
    Screenshot 2024-01-27 085918.jpg
    122.6 KB · Views: 16
@globosud: Probably enough to remove the isthmus check in the DLL path finding code; should be this line. Well, the whole block after "Might want to take this out..." could be removed. (Although that's probably not what the comment intends to convey, just to be clear. I think it means to say that the line with the domain check might be redundant or that the movement restriction should also apply to land units moving between transports.) I doubt that anything can be done without recompiling the DLL. Edit: And I see you've been using Realism Invictus. That mod should have isthmus checks in a couple of other places, namely, in the same file, in stepValid (added by BBAI) and in pathValid_join (function added by K-Mod).
--
Can't answer the previous two questions.
 
Last edited:
Thanks for the reply
I partially solved the problem by activating <bCanMoveAllTerrain>1</bCanMoveAllTerrain>for all ships and then making all terrain impassable, but unfortunately a problem remains, in culturally controlled terrain the ships do not respect the restrictions, how can I make sure that the terrain remains impassable even if culturally controlled. for example
 

Attachments

  • Screenshot 2024-01-27 102013.png
    Screenshot 2024-01-27 102013.png
    638.7 KB · Views: 17
Ah, that's a creative solution. Could negatively affect performance; perhaps run some late-game test sometime if that worries you. The rule is implemented in CvUnit::canMoveInto. A unit is prohibited from entering a tile if the tile's terrain or feature is set to impassable for the unit in XML, the unit's team does not have a tech to override that (Astronomy for Ocean), and it's either not a sea unit or its team does not own the tile. Doesn't look like this can be worked around through XML, at least not this particular chunk of code. There's a Python callback (at the end of canMoveInto) that should allow reimplementing the Terrain/Feature-Impassable XML tags in Python without an exception for owned tiles. That will likely come with a performance penalty as the callback is normally disabled (USE_UNIT_CANNOT_MOVE_INTO_CALLBACK).
 
USE_UNIT_CANNOT_MOVE_INTO_CALLBAC
thanks for your availability.
so I just need to insert 1 instead of 0 in the "PythonCallbackDefines" file under USE_UNIT_CANNOT_MOVE_INTO_CALLBACK? maybe I need to insert some string into CvGameUtils too?
I hope I understood correctly, because unfortunately I don't understand anything about phyton and sdk.
 
Last edited:
That'll only enable the call to Python, you'd still need to write Python code that does the same thing as the C++ code I linked to except that it doesn't make an exception for tile ownership. The DLL-to-Python call should reach unitCannotMoveInto in Assets\Python\EntryPoints\CvGameInterface.py. From there, if it's a BUG-based mod, it'll be forwarded to BugGameUtils.py, otherwise to CvGameUtils.py. I never figured out how exactly BUG handles Python callbacks; presumably you could just place your code directly in CvGameInterface.py. But it sounds like that's not really workable – if you're totally unfamiliar with Python.
 
CvGameUtils
That'll only enable the call to Python, you'd still need to write Python code that does the same thing as the C++ code I linked to except that it doesn't make an exception for tile ownership. The DLL-to-Python call should reach unitCannotMoveInto in Assets\Python\EntryPoints\CvGameInterface.py. From there, if it's a BUG-based mod, it'll be forwarded to BugGameUtils.py, otherwise to CvGameUtils.py. I never figured out how exactly BUG handles Python callbacks; presumably you could just place your code directly in CvGameInterface.py. But it sounds like that's not really workable – if you're totally unfamiliar with Python.

I have to hope to find some code to adapt, or some person to write it for me. Thanks to the availability
 
Top Bottom