RFC Modding Central

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
 
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.
 
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.
 
Function of RFC Python Files:

AIWars - scripting AI war declaration
Barbs - spawning units and cities for the minor players
CityNameManager - naming cities according to Civ/geography
Communications - connects/disconnects contact between players, embassies
Congresses - World Congresses
Conts - settings and global values (constants)
CvEventManager - part of the core game mechanisms
CvGameUtils - also part of the core game mechanisms
CvRFCEventHandler - main hub for Python calls in RFC
CvRFCEventManager - another event management module, not really in use
Plague - plagues? :rolleyes:
Religions - spreading of religions, holy shrines
Resources - scripted spreading of Bonuses and terrain
RFCUtils - collection of useful Python code for RFC, shared by several modules
RiseAndFall - central module for main RFC features (like Rise and Fall, secessions, collapse of minor Civs)
Stabilty - calculation and handling of stability, stability based collapse of Civs
StoredData - custom stored data for RFC
UniquePowers - some of the Unique Power code (rest in DLL)
Victory - Unique Historical Victories
 
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.
 
(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)
 
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.
 
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.
 
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.
 
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.
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.
 
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?
 
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?

oops i didn't read the last line of the error, it seems it has something to do with units.
 
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.
 
@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.
 
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.
 
Here's a guess - do they have proper captails (i.e. with Palace in cities pre-placed in WBSave?)
 
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.
 
Top Bottom