Modders Guide to FfH2

Is the python function, cannotTrain being incorrectly used? Looking through the DLL, this function is only called from the canUpgrade function. However, the pyton has lots of code checking for existing numbers of units such as the following snippet:

Code:
if eUnit == gc.getInfoTypeForString('UNIT_DEMAGOG'):
	if pPlayer.getUnitClassCount(gc.getInfoTypeForString('UNITCLASS_DEMAGOG')) > 6:
		return True

The section of this code is obviously meant for the AI, but if I understand it correctly, it's telling the AI to not upgrade Demagogs if it has more then 6 Demagogs, which doesn't seem to make much sense. Am I misunderstanding what this code is doing?
 
Is the python function, cannotTrain being incorrectly used? Looking through the DLL, this function is only called from the canUpgrade function. However, the pyton has lots of code checking for existing numbers of units such as the following snippet:

Code:
if eUnit == gc.getInfoTypeForString('UNIT_DEMAGOG'):
	if pPlayer.getUnitClassCount(gc.getInfoTypeForString('UNITCLASS_DEMAGOG')) > 6:
		return True

The section of this code is obviously meant for the AI, but if I understand it correctly, it's telling the AI to not upgrade Demagogs if it has more then 6 Demagogs, which doesn't seem to make much sense. Am I misunderstanding what this code is doing?

It blocks the AI from Upgrading too many Units to Demagogs, which makes sense since they will leave AI after Crusade is over. It does not block the AI from Upgrading Demagogs to something else.
 
It blocks the AI from Upgrading too many Units to Demagogs, which makes sense since they will leave AI after Crusade is over. It does not block the AI from Upgrading Demagogs to something else.

OK. That makes more sense. But why are there also checks for Settlers, Workers and Scouts (among other things). No units upgrade into these unit types.

Here's one example:

Code:
if eUnit == gc.getInfoTypeForString('UNIT_SETTLER'):		
	if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_KHAZAD'):
		if pPlayer.getUnitClassCountPlusMaking(gc.getInfoTypeForString('UNITCLASS_SETTLER')) > 0:
			if eTeam.isHasTech(gc.getInfoTypeForString('TECH_FESTIVALS')) == False:
				return True


Edit: And actually, after looking at UnitInfos.xml, no units upgrade into Demagogs either. They're a static unit class.


Edit2: And there's a section for Loki?!?

Code:
if eUnitClass == gc.getInfoTypeForString('UNITCLASS_LOKI'):
	if eTeam.isHasTech(gc.getInfoTypeForString('TECH_FESTIVALS')) == False:
		return True
 
as deanej pointed out, cannottrain is not only used for upgrading, but also for training. if the cannottrain callback returns true, a unit cannot be trained in that city.
 
If I wanted to add a free specialist of a certain type to a city when a certain unit type enters it and than remove it as soon as it leaves how would I best do it?

I was considering trying to make an auto cast spell that triggers when the unit type enters a city. But I am unsure if a spell can add specialists like that.
 
I'm trying to add the Entertain spell to the global defines in the DLL. It compiles fine, but when I start up FFH2, I get the following XML error:

[6216.593] info type ,CLASÿÿÿÿ not found, Current XML file is: xml\Units/CIV4SpellInfos.xml

To try and do this, I simply copied and pasted the existing code for the disrupt spell as follows in CvXMLLoadUtilitySet.cpp:

Code:
      SetGlobalDefine("SPELL_ENTERTAIN", szVal);
        idx = FindInInfoClass(szVal);
        GC.getDefinesVarSystem()->SetValue("SPELL_ENTERTAIN", idx);

If I take this code out, the error goes away.


EDIT: I figured it out. I had to also add those values to the GlobalDefinesAlt.xml file
 
Advancing on my last question.
I worked out how to add the specialist when the unit moves into a city.
Spoiler :

def onMovePPQ(pCaster, pPlot):
pCity = pCaster.plot().getPlotCity()
if pCity.getTeam() == caster.getTeam():
if pCaster.getUnitType() == gc.getInfoTypeForString('unit type I want'):
iSpec = gc.getInfoTypeForString('specialist type I want')
iS = pCity.getFreeSpecialistCount(gc.getInfoTypeForString('specialist type I want'))
iS++
pCity.changeFreeSpecialistCount(iSpec, iS)

indentation is broken here for some reason


Now I get that I will have to conect my function with the onMove function just like others are. But I also need a second function to remove the specialist.

The problem I face is how do i check if a unit has just left a city? :eek:


Also, has anyone made anything like this before?
 
The problem I face is how do i check if a unit has just left a city? :eek:

It would probably be easier to tie the whole thing to the city. The city should do the check to see if units with this promotion are in the city, at which point it adds the specialists, removing them the next time it checks and that unit isn't present.
 
To get proper indention use [code]Put your code here[/code]
 
It would probably be easier to tie the whole thing to the city. The city should do the check to see if units with this promotion are in the city, at which point it adds the specialists, removing them the next time it checks and that unit isn't present.

What function would that be than? :(
 
What function would that be than? :(

Why don't you make it work like the Hope or Inspiration spell, which create buildings that check whether the caster is still in the city. You just don't create a "Hope"-like building, but rather a building similar to the Great Library.
 
What function would that be than? :(

Maybe on CvEventManager.py, onCitydoTurn? That is where the code for Citadel of Light, Hall of Mirrors and Planar Gate are.

The code would be something like this, I think:

Code:
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if (pUnit.getOwner() == pCity.getOwner() and pUnit.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_XYZ')):
			specialist = true
	if specialist:
		iSpec = gc.getInfoTypeForString('specialist type you want')
		iS = pCity.getFreeSpecialistCount(gc.getInfoTypeForString('specialist type you want'))
		iS++
		pCity.changeFreeSpecialistCount(iSpec, iS)
 
Why don't you make it work like the Hope or Inspiration spell, which create buildings that check whether the caster is still in the city. You just don't create a "Hope"-like building, but rather a building similar to the Great Library.
Because I want it to be stackable. As in 10 units = 10 specialists. You can't do that with buildings.

Maybe on CvEventManager.py, onCitydoTurn? That is where the code for Citadel of Light, Hall of Mirrors and Planar Gate are.

The code would be something like this, I think:

Code:
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if (pUnit.getOwner() == pCity.getOwner() and pUnit.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_XYZ')):
			specialist = true
	if specialist:
		iSpec = gc.getInfoTypeForString('specialist type you want')
		iS = pCity.getFreeSpecialistCount(gc.getInfoTypeForString('specialist type you want'))
		iS++
		pCity.changeFreeSpecialistCount(iSpec, iS)

Thanks. By reading I take it that the thing adds specialists to a city based on the said units when ever the turn is being calculated (start/end/who knows). So by reading it, I think of using something like this:

Code:
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if (pUnit.getOwner() == pCity.getOwner() and pUnit.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_XYZ')):
				iSpec = gc.getInfoTypeForString('specialist type I want')
				iS = pCity.geUnitCount(gc.getInfoTypeForString('UNITCLASS_XYZ'))
				pCity.changeFreeSpecialistCount(iSpec, iS)
Am I correct that this should set the number of specialists to the number of units of said type? (noting that geUnitCount needs to be changed to what ever the actual function is called like)
 
Code:
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if (pUnit.getOwner() == pCity.getOwner() and pUnit.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_XYZ')):
				iSpec = gc.getInfoTypeForString('specialist type I want')
				[B]iS += 1[/B] 
				pCity.changeFreeSpecialistCount(iSpec, iS)
Am I correct that this should set the number of specialists to the number of units of said type? (noting that geUnitCount needs to be changed to what ever the actual function is called like)

I think this would work. IIRC, your version will add x number of specialist for x number of units. So the total specialists would be x*x. I was using specialist = true so that the function will add only one specialist regardless of how many UNITCLASS_XYZ.
 
lolz, how did that skip my mind. After 8 years of programing things like that should not be happening to me.


Either way, another question. Can anyone tell me just when the onCitydoTurn function triggers?
Beginning or end of the turn?
 
Either way, another question. Can anyone tell me just when the onCitydoTurn function triggers?
Beginning or end of the turn?

It's at the beginning of your turn. The citadel of light will "Pillar-of-Light-ized" your opponents at the beginning of your turn, so does the Hall of Mirror's effect.

Edit : don't forget to add another function to remove your specialists when no UNITCLASS_XYZ is in the city. :goodjob:
 
Hello All --

Question about modifying the Sevopedia. I have a "Unit Upgrade" screen that I am working on. I can already get the screen to come up, and unit dependencies are (mostly) properly linked. What I'd like to do now is make the screen more intelligent by letting a user first select a Civ and then have the promotion tree hide units that are not available to that Civ but also emphasize UUs.

I've been able to figure out how to modify the screen call in SevoPediaMain.py to call up the list of Civs, but now can't seem to find out how to make up the call to the screen that I want to use after the user clicks the specific civ.

I would like to do something like this (I'm just hacking Python here badly, forgive the pseudocode):

Code:
self.CreateScreen(CivType)

This code works to create the screen without giving any civ-specific info, just shows all units:
Code:
		screen = self.getScreen()
		self.getScreen().deleteWidget("PediaMainItemList")
		self.UPGRADES_GRAPH_ID = self.getNextWidgetName()
		screen.addScrollPanel(self.UPGRADES_GRAPH_ID, u"", self.X_ITEMS, self.Y_PEDIA_PAGE - 13, self.W_SCREEN - self.X_ITEMS, self.H_PEDIA_PAGE + 2, PanelStyles.PANEL_STYLE_STANDARD)
		screen.setActivation(self.UPGRADES_GRAPH_ID, ActivationTypes.ACTIVATE_NORMAL)
		upgradesGraph = UnitUpgradesGraph.UnitUpgradesGraph(self)
		upgradesGraph.getGraph()
		upgradesGraph.drawGraph()

This works to get the list of Civs, but just ends up being a copy of the Civiliation list information screen:

Code:
		self.list = self.getCivilizationList()
		self.placeItems(WidgetTypes.WIDGET_PEDIA_JUMP_TO_CIV, gc.getCivilizationInfo)

How do I hybridize the two? Do I have to do DLL work, seems like the widget types are defined there but I really don't have any idea what to make of them.
 
yes, the widgets are defined in the pedia.

search for "self.mapScreenFunctions" in SevoPediaMain.py, maybe that helps.
 
Back
Top Bottom