1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

RFC Modding Central

Discussion in 'Rhye's and Fall Modmods' started by Linkman226, Aug 29, 2011.

  1. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
  2. BenZL43

    BenZL43 awkward cat

    Joined:
    Sep 25, 2010
    Messages:
    3,199
    Gender:
    Male
    Location:
    Indonesia
    Thanks.
    What does 0 10 etc mean ? Larger the number means its more agressive there?
    What is the maximum (and minimum) value?

    Btw
    Congratulation on making this Sticky :p
     
  3. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    Yes, the higher it is the more likely it is.

    And this was stickied?! Yay! Mods who are reading this, which one of you was it? I'd like to send you my thanks.
     
  4. Leoreth

    Leoreth 心の怪盗団 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    33,886
    Gender:
    Male
    Location:
    Leblanc
    Rhye usually uses 10 for a civ's home territory (so they're going to reconquer it), 8 or 6 for areas they were fairly expansionist towards and 4 or 2 for other regions they held at some point.
     
  5. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    Function of RFC Python Files:

     
  6. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    Overlay Map Information:

    Settler Maps- CvRhyes.cpp:
    The stability values and for each tile and the probability of the Ai=I settling on that tile are controlled by the Settler Maps

    City Name Manager (CNM)- CityNameManager.py

    The name of a city when it is founded on a given plot is controlled here, based on its x, y coordinates

    AIWars- AIWars.py
    AIWars works the same way as CNM, but the value of each tile indicates how likely it is that the given civ will go to war with the civ that controls that tile.
    One important thing to know about AIWars is that it only controls against whom war is declared, not on which area the AI focuses its military efforts during these wars.
    Rhye usually uses 10 for a civ's home territory (so they're going to reconquer it), 8 or 6 for areas they were fairly expansionist towards and 4 or 2 for other regions they held at some point.
     
  7. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    (The two posts above are for quick access via URL from the OP. I'll keep them updated as others posts questions and they are answered)
     
  8. civ-addicted

    civ-addicted King

    Joined:
    Aug 8, 2009
    Messages:
    852
    Location:
    The City of the Lion
    Is anyone else using modifiers which are exported to python? I could write up how i did it resp. how Rhye did it for RFC:GW.
     
  9. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    Sure, can you? Thanks.
     
  10. civ-addicted

    civ-addicted King

    Joined:
    Aug 8, 2009
    Messages:
    852
    Location:
    The City of the Lion
    Okay, here it goes.

    How it works:
    First of all, there must be an array with all the values (f.e. tWorkRateModifier, which has values how fast the Worker does his thing). A function in EntryPoints\CvScreensinterface.py (f.e. getWorkRateModifier()) will recieve an index and returns the corresponding value of the array. The C++ code will call this function (f.e. in CvUnit::workRate()) and return this value again and compute in the code.

    How to set it up:
    First of all, create all the arrays in Const.py: (just copy-paste)
    Spoiler :
    Code:
    tUnitCostModifier = ( #lower the cheaper
    
    )
    
    
    tResearchModifier = ( #lower the faster
    
    )
    
    tDistanceMaintenanceModifier = ( #lower the better
    
    )
    
    tNumCitiesMaintenanceModifier = ( #lower the better
    
    )
    
    tCivicUpkeepModifier = ( #lower the better
    
    )
    
    tHealthBonusModifier = ( 
    
    ) 
    
    tGrowthModifier = ( #lower the faster
    
    ) 
    
    tUnitProductionModifier = ( #lower the faster
    
    )
    
    tWonderProductionModifier = ( #lower the faster
    
    )
    
    tBuildingProductionModifier = ( #lower the faster
    
    )
    
    
    tInflationModifier = ( #lower the better
    
    )
    
    tGreatPeopleModifier = ( #lower the faster
    
    )
    
    tCitiesStartEraModifier = ( #higher the better
    
    )
    
    
    tWarDistanceModifier = ( #higher the closer, lower the further
    
    )
    
    
    tCityClosenessModifier = ( #higher the closer 7-14
    
    )
    
    tStabilityFoundModifier = ( #higher the more likely to use civic
    
    )
    
    tStabilityConquestModifier = ( #higher the more likely to use civic
    
    )
    
    tStabilityCommerceModifier = ( #higher the more likely to use civic
    
    )
    
    
    tCommerceGrowthModifier = ( #higher the faster
    
    )
    
    tWorkRateModifier = ( #higher the faster
    
    )
    
    Second of all, you need to define the python methods: (copy-paste as well)
    Spoiler :
    Code:
    def getStartingTurn(argsList):
            return con.tBirth[argsList[0]]
    def getSettlersMaps(argsList):
            return SettlersMaps.tSettlersMaps[argsList[0]][argsList[1]][argsList[2]]              
    def getUnitCostModifier(argsList):
            return con.tUnitCostModifier[argsList[0]]
    def getResearchModifier(argsList):
            return con.tResearchModifier[argsList[0]]
    def getDistanceMaintenanceModifier(argsList):
            return con.tDistanceMaintenanceModifier[argsList[0]]
    def getNumCitiesMaintenanceModifier(argsList):
            return con.tNumCitiesMaintenanceModifier[argsList[0]]
    def getCivicUpkeepModifier(argsList):
            return con.tCivicUpkeepModifier[argsList[0]]
    def getHealthBonusModifier(argsList):
            return con.tHealthBonusModifier[argsList[0]]
    def getGrowthModifier(argsList):
            return con.tGrowthModifier[argsList[0]]
    def getUnitProductionModifier(argsList):
            return con.tUnitProductionModifier[argsList[0]]
    def getWonderProductionModifier(argsList):
            return con.tWonderProductionModifier[argsList[0]]
    def getBuildingProductionModifier(argsList):
            return con.tBuildingProductionModifier[argsList[0]]
    def getInflationModifier(argsList):
            return con.tInflationModifier[argsList[0]]
    def getGreatPeopleModifier(argsList):
            return con.tGreatPeopleModifier[argsList[0]]
    def getCitiesStartEraModifier(argsList):
            return con.tCitiesStartEraModifier[argsList[0]]
    def getWarDistanceModifier(argsList):
            return con.tWarDistanceModifier[argsList[0]]
    def getCityClosenessModifier(argsList):
            return con.tCityClosenessModifier[argsList[0]]
    def getStabilityFoundModifier(argsList):
            return con.tStabilityFoundModifier[argsList[0]]
    def getStabilityConquestModifier(argsList):
            return con.tStabilityConquestModifier[argsList[0]]
    def getStabilityCommerceModifier(argsList):
            return con.tStabilityCommerceModifier[argsList[0]]
    def getCommerceGrowthModifier(argsList):
            return con.tCommerceGrowthModifier[argsList[0]]
    def getWorkRateModifier(argsList):
            return con.tWorkRateModifier[argsList[0]]
    
    Copy this methods into the same block as getStartingTurn(), getSettlerMaps() etc. in EntryPoints\CvScreensinterface.py.

    The last and the least fun part comes now.
    Everyone of those methods will have a place in the C++ code where it is called. Look up in the Spoiler to know which value has which python method and is called in which C++ method
    Spoiler :
    Code:
    python array				python method					c++ method
    
    tUnitCostModifier			getUnitCostModifier(argsList):			CvHandicapInfo::getUnitCostPercentByID
    							
    tResearchModifier 			getResearchModifier(argsList):			CvHandicapInfo::getResearchPercentByID
    							
    tDistanceMaintenanceModifier 		getDistanceMaintenanceModifier(argsList):	CvHandicapInfo::getDistanceMaintenancePercentByID
    							
    tNumCitiesMaintenanceModifier 		getNumCitiesMaintenanceModifier(argsList):	CvHandicapInfo::getNumCitiesMaintenancePercentByID
    							
    tCivicUpkeepModifier 			getCivicUpkeepModifier(argsList):		CvHandicapInfo::getCivicUpkeepPercentByID
    							
    tHealthBonusModifier			getHealthBonusModifier(argsList):		CvHandicapInfo::getHealthBonusByID
    							
    tGrowthModifier				getGrowthModifier(argsList):			CvPlayer::getGrowthThreshold
    							
    tUnitProductionModifier			getUnitProductionModifier(argsList):		CvPlayer::getProductionNeeded(UnitTypes eUnit)
    							
    tWonderProductionModifier		getWonderProductionModifier(argsList):		CvPlayer::getProductionNeeded(BuildingTypes eBuilding)
    							
    tBuildingProductionModifier 		getBuildingProductionModifier(argsList):	CvPlayer::getProductionNeeded(BuildingTypes eBuilding)
    							
    tInflationModifier 			getInflationModifier(argsList):			CvPlayer::calculateInflationRate
    							
    tGreatPeopleModifier 			getGreatPeopleModifier(argsList):		CvPlayer::greatPeopleThreshold
    							
    tCitiesStartEraModifier 		getCitiesStartEraModifier(argsList):		CvCity::init
    							
    tWarDistanceModifier 			getWarDistanceModifier(argsList):		CvPlayerAI::AI_militaryWeight
    							
    tCityClosenessModifier 			getCityClosenessModifier(argsList):		CvPlayerAI::AI_foundValue
    							
    tStabilityFoundModifier 		getStabilityFoundModifier(argsList):		CvPlayerAI::AI_civicValue
    							
    tStabilityConquestModifier 		getStabilityConquestModifier(argsList):		CvPlayerAI::AI_civicValue
    							
    tStabilityCommerceModifier 		getStabilityCommerceModifier(argsList):		CvPlayerAI::AI_civicValue
    							
    tCommerceGrowthModifier 		getCommerceGrowthModifier(argsList):		CvCity::doCulture
    							
    tWorkRateModifier 			getWorkRateModifier(argsList):			CvUnit::workRate
    
    


    If you look into the c++ code, you will see that there is at least one "switch" block in every one of the above methods. Rhye already gave every civ a certain value.
    The next step is to look closely to the code: you will notice that every Civ will get it's value here. I'll show it for tUnitProductionModifier, the value that changes the cost for units.
    Look up into CvPlayer::getProductionNeeded(UnitTypes eUnit) and search for the switch: it starts with "//Rhye - start switch" and ends with "//Rhye - end". Comment it out using /* and */. But beware! The chinese UP is in here, you better extract that. I took that example to show you that whatever guide you use you still have to use your own brain :)
    For the next step, include this code right after what you've commented out:
    Code:
    	long result = -1;
    	CyArgsList argsList;
    	argsList.add(getID());
    	gDLL->getPythonIFace()->callFunction(PYScreensModule, "getUnitProductionModifier", argsList.makeFunctionArgs(), &result);
    	int iResult = (int)result;
    
    	if (getID()<NUM_MAJOR_PLAYERS)
    		iProductionNeeded = iProductionNeeded*result/100;
    
    The first line is a basic definition, while the -1 is for error handling purposes.
    The second line is always the same.
    The third line appends a value to the object in line 2. Attention: this is a bit tricky. Since your in the class CvPlayer, there is a method getID() which returns the corresponding value for every Civilization. Egypt is 0, India is 1 etc. If you're in CvUnit, you'll need getOwner() or getOwnerINLINE().
    The fourth line is the operative point. Here is where the DLL calls the python method and assigns a new value to "result" (the '&' is essential!)
    The fifth line converts result (i just see that it's not really necessary...)
    The if clause makes sure that only major players will get this treatment.
    The last line computes the value.

    Now as the final step, copy all the values from the DLL into the python module. In the case of tUnitProductionModifier it will look something like this:
    Spoiler :
    Code:
    tUnitProductionModifier = ( #lower the faster
    110, #Egypt
    105, #India
    110, #China
    115, #Babylonia
    110, #Greece
    88, #Persia
    110, #Carthage
    105, #Rome
    93, #Japan
    95, #Ethiopia
    105, #Maya
    85, #Vikings
    92, #Arabia
    95, #Khmer
    95, #Spain
    92, #France
    95, #England
    80, #Germany
    85, #Russia
    90, #Netherlands
    90, #Mali
    88, #Turkey
    90, #Portugal
    105, #Inca
    80, #Mongolia
    108, #Aztecs
    83, #America
    200,
    200,
    150,
    150,
    140
    )
    
    

    The basic idea behind this guide is to show how to read a python value into the DLL. You'll need about the same code as above, but every case needs a unique treatment.
     
  11. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    :goodjob:

    Awesome
     
  12. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,038
    Location:
    Toronto
    I'm trying to figure out why I'm getting this python exception, which occurs at the start of the game just as the main screen comes up:

    File "CvWBInterface", line 18, in writeDesc

    File "CvWBDesc", line 1545, in write

    File "CvWBDesc", line 1193, in write

    File "CvWBDesc", line 804, in write

    AttributeError: 'NoneType' object has no attribute 'GetType'

    line 804 in CvWBDesc says: unitType = gc.getUnitInfo(unit.getUnitType()).getType()

    does this mean it can't find the unit type of one of the units on the map?

    edit: by elimination I've discovered it was Javelinmen in the starting units in RiseAndFall.py causing the error. they also cause this:

    Spoiler :
    Traceback (most recent call last):

    File "CvEventInterface", line 22, in onEvent

    File "CvCustomEventManager", line 146, in handleEvent

    File "CvCustomEventManager", line 157, in _handleDefaultEvent

    File "CvRFCEventHandler", line 91, in onGameStart

    File "RiseAndFall", line 330, in setup

    File "RiseAndFall", line 1981, in createEarlyStartingUnits

    File "RiseAndFall", line 1710, in createStartingUnits

    File "RFCUtils", line 567, in makeUnit

    RuntimeError: unidentifiable C++ exception
    ERR: Python function onEvent failed, module CvEventInterface


    which crashes the game on the next turn.

    that unit is unchanged from previously working versions, so I'm confused as to where to look for a problem.
     
  13. Kubko

    Kubko Chieftain

    Joined:
    Sep 25, 2010
    Messages:
    59
    you have more/less of civilizations than you defined in CvDefines.h, if you have more than you have defined you need to increase the array size, if you have less you need to decrease it.
     
  14. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,038
    Location:
    Toronto
    In CvDefines.h I only find MAX_CIV_PLAYERS (35). This is the same as Sword of Islam and I have the same number of civs, just changed the names. If this is caused by the number of civs why would it only happen with certain units?
     
  15. Kubko

    Kubko Chieftain

    Joined:
    Sep 25, 2010
    Messages:
    59
    oops i didn't read the last line of the error, it seems it has something to do with units.
     
  16. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,038
    Location:
    Toronto
    A bit more detail about the above errors:

    they happen if either iJavelinman, iHorseman or iHorseArcher are included in a unit spawn via python, either as barbs or civ starting units. I can still build those units or place them via WB and get no errors.
     
  17. embryodead

    embryodead Caliph

    Joined:
    Jan 1, 2003
    Messages:
    5,179
    Location:
    basement
    @srpt

    Go in-game, python console and try this:

    from Consts import *
    print iJavelinman
    print gc.getInfoTypeForString("UNIT_JAVELINMAN")

    This way you'll be able to check if the python index matches the xml index. I suspect it doesn't.
     
  18. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,038
    Location:
    Toronto
    Thanks problem solved. Here's a another strange one:

    all the civs that start with cities on the map, which is 10 of them, display 3 things:

    1. they can't hire mercenaries. the screen offers them and you can click on them and make them appear as hired in the lower part of the screen and the python log says they've been hired, but they don't appear in the game.

    2. war declaration on spawn via python doesn't affect them.

    3. they don't get invasion alerts when they should.

    these things don't generate any errors and all work normally for the other civs.
     
  19. embryodead

    embryodead Caliph

    Joined:
    Jan 1, 2003
    Messages:
    5,179
    Location:
    basement
    Here's a guess - do they have proper captails (i.e. with Palace in cities pre-placed in WBSave?)
     
  20. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,038
    Location:
    Toronto
    some do and some don't but they are all affected. 4 of them, the 1st, 3rd, 5th and 6th, start with 3-8 cities plus a spawn of units in their capital (with palaces in the WB save), the others just spawn in an empty tile with settlers. is it better to have only 1 civ start with cities? I always wondered why the Abbasids flip their starting cities in SoI rather than just start with them.

    edit: I've now rearranged the order of civs so the first 4 start with cities and the next 6 with settlers, with the same results as above, but I thought I'd mention that contact on spawn is working for these civs.

    I also think that civs are not collapsing when they should. in one autoplay the Mauryans had conquered all of SE Asia and China by 50AD, all outside of their border provinces, and hadn't collapsed.

    and more strange results: when cities flip to new civs their defenders are deleted.
     

Share This Page