Modders Guide to FfH2

Alright, another question. Trying to set up a randLeash, like I mentioned in my last post. Loading it onto the unit is working... The problem is removal.

I'm running a rand from 0 to the LeashChance on the promotion, and changing the Leash by that value. Problem is it's random again when removed. Is there any way you know of to remove the SAME value, and do so in a way that allows for multiple LeashChance promotions?

If not, I'm going to remove the mechanic; If it can bug the rest of the system this easily, it's best to avoid it.
 
Bah, don't ask a question in two places :p Though technically you hadn't actually asked in the other, just alluded to having asked here. But I read that first so responded there, but others might be interested in the answer :p


Best way I can think of is an int array in CvUnit of NumPromotionInfos size which will store the assigned random value. Then on removal of any promotion you check for a non-zero value here instead of checking for a non-zero random range in PromotionInfo. And after the value is checked and removed if needed, set it back to zero.
 
I am trying to add some code in Aichooseproduction that checks what the terrain within the cityradius looks like. I have borrowed the code that checks the terrain around the capital in Aichoosetech. But the game stops using Aichooseproduction as soon as i activate those for-inrange lines so something must be wrong there. But those lines comes straight from Aichoosetech. Anyone have any idea what i am missing?
Spoiler :
added to Aichooseproduction:
#check what is in the cityradius
iX=pCity.getX()
iY=pCity.getY()

# for iiX in range(iX-2, iX+3, 1):
# for iiY in range(iY-2, iY+3, 1):
# do the stuff i want
 
Can you please put your code in
Code:
 tags, so that indentation is preserved?

And don't just post that code- please also show where in AI_chooseProduction() you added your code.
 
I am trying to add some code in Aichooseproduction that checks what the terrain within the cityradius looks like. I have borrowed the code that checks the terrain around the capital in Aichoosetech. But the game stops using Aichooseproduction as soon as i activate those for-inrange lines so something must be wrong there. But those lines comes straight from Aichoosetech. Anyone have any idea what i am missing?
Spoiler :
added to Aichooseproduction:
#check what is in the cityradius
iX=pCity.getX()
iY=pCity.getY()

# for iiX in range(iX-2, iX+3, 1):
# for iiY in range(iY-2, iY+3, 1):
# do the stuff i want

It's hard to find out what's wrong from your post. Here is some code that works to teach the AI how to use the temple of the hand by checking surrounding terrain:
Spoiler :
Code:
		if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_ILLIANS'):
			if pCity.getNumBuilding(gc.getInfoTypeForString('BUILDING_TEMPLE_OF_THE_HAND')) == 0:
				print ("Illian snowtemple check")
				iTemple = gc.getInfoTypeForString('BUILDING_TEMPLE_OF_THE_HAND')
				iFloodPlains = gc.getInfoTypeForString('FEATURE_FLOOD_PLAINS')
				iJungle = gc.getInfoTypeForString('FEATURE_JUNGLE')
				iScrub = gc.getInfoTypeForString('FEATURE_SCRUB')
				iTundra = gc.getInfoTypeForString('TERRAIN_TUNDRA')
				iDesert = gc.getInfoTypeForString('TERRAIN_DESERT')
				iSnowcounter = 0
				for iI in range(1, 21):
					pLoopPlot = pCity.getCityIndexPlot(iI)
					if pLoopPlot:
						print iSnowcounter
						if not pLoopPlot.isNone():
							if not pLoopPlot.isWater():
								if pLoopPlot.getTerrainType() == iTundra:
									iSnowcounter += 1
								if pLoopPlot.getTerrainType() == iDesert:
									iSnowcounter += 1
								iFeature = pLoopPlot.getFeatureType()
								if iFeature == iJungle:
									iSnowcounter += 1
								if iFeature == iFloodPlains:
									iSnowcounter -= 3
								if iFeature == iScrub:
									iSnowcounter += 1
								if pLoopPlot.isRiverSide():
									iSnowcounter -= 1
				if iSnowcounter>=1:
					if pPlot.getNumUnits() >= 2:
						if pCity.canConstruct(iTemple,False,False,False):
							pCity.pushOrder(OrderTypes.ORDER_CONSTRUCT, iTemple, -1, False, False, False, False)
							print ("Ice Temple built")
							bOverride = true
							return bOverride[/SPOILER]
 
Nevermind i made a to stupid a misstake to mention.

How can i test if a plot is a fresh water lake? It cant find what it is defined as.

I noticed the Bals AI doesn't seem to use his Freaks to constuct freak shows. I am not to familiar with that part of the the coding to check if it was just a coincident but i think i am right. Is there a simple way to find out and in case change that?
 
Is there a way to boost Specialist yield just in one city, and not globally? If yes, what field do i want to edit?

What I'm trying to do is make an Alchemy Lab replacement that gives +1 Research to Sages and Great Sages in the city that the building is built. At the moment, the only example XML that I've found that does what I want is the Great Library or Angkor Wat, both of which apply the change globally. [It's <SpecialistCommerceChanges> for the former, and <SpecialistYieldChanges> for the latter.] A global change is too powerful for a mere building, and my intent is to encourage the player to make SE Science cities when playing this custom civilization. So one has to build this building in each science city one has, and not build it once and get the effects in all your cities.
 
Why can't I get my mercenary-hiring spell to work when I try to create the units in python?

I have it working in a Mangadine-Hire Units -like spell-triggered event, but I don't want the mercenaries to be of the caster's civ's UUs or with the default race. Having each mercenary able to summon another one seems potentially too powerful too, so I'm thinking it is better to immobilize new hires for a turn. I've tried python code like this, but it isn't generating any units.
Code:
def doGuildMercChamp(argslist):
	iEvent = argsList[0]
	kTriggeredData = argsList[1]
	pPlayer = gc.getPlayer(kTriggeredData.ePlayer)
	pCity = pPlayer.getCity(kTriggeredData.iCityId)
	iPromotion = -1
	iUnit = gc.getInfoTypeForString('UNIT_CHAMPION')
	iRnd = CyGame().getSorenRandNum(100, "Slave Trade Buy")
	if (iRnd >= 30 and iRnd < 35):
		iUnit = gc.getInfoTypeForString('UNIT_DRAGON_SLAYER')
	if (iRnd >= 35 and iRnd < 50):
		iUnit = gc.getInfoTypeForString('UNIT_BATTLEMASTER')
		iPromotion = gc.getInfoTypeForString('PROMOTION_WINTERBORN')
	if (iRnd >= 55 and iRnd < 60):
		iPromotion = gc.getInfoTypeForString('PROMOTION_BOARDING')
	if (iRnd >= 60 and iRnd < 65):
		iUnit = gc.getInfoTypeForString('UNIT_MIMIC')
	if (iRnd >= 65 and iRnd < 70):
		iPromotion = gc.getInfoTypeForString('PROMOTION_ELF')
	if (iRnd >= 70 and iRnd < 75):
		iPromotion = gc.getInfoTypeForString('PROMOTION_ELF_DARK')
	if (iRnd >= 70 and iRnd < 75):
		iPromotion = gc.getInfoTypeForString('PROMOTION_DWARF')
	if iRnd > 75:
		iPromotion = gc.getInfoTypeForString('PROMOTION_ORC')
		iUnit = gc.getInfoTypeForString('UNIT_OGRE')


	newUnit = pPlayer.initUnit(iUnit, pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
	newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MERCENARY'), True)
	newUnit.changeImmobileTimer(1)
	iRace = newUnit.getRace()
	newUnit.setHasPromotion(iRace, False)
	newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_VALOR'), False)
	if iPromotion != -1:
		newUnit.setHasPromotion(iPromotion, True)
 
Why can't I get my mercenary-hiring spell to work when I try to create the units in python?

Well, I don't know what makes your spell failed but I do find something strange here :

Code:
	[B]if (iRnd >= 70 and iRnd < 75):
[/B]		iPromotion = gc.getInfoTypeForString('PROMOTION_ELF_DARK')
	[B]if (iRnd >= 70 and iRnd < 75):
[/B]		iPromotion = gc.getInfoTypeForString('PROMOTION_DWARF')

Would this makes you get two race if you roll 70<x<75?
 
Ok, got another problem ;)

I am trying to add building replacement mechnics - so i.e. palisade gets removed after building walls and can't be build if walls are in the city. I had ti working in python for a long time, but I plan to expand this a bit so dll would be great way to do it.

So, I have added a tag ReplacesBuildingClass. It works fine for the removal part, but I can't find a way to make it block rebuilding of the building.

The code was added just below BuildingClassNeededInCity part of CanConstruct in CvCity.cpp
Code:
		for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
		{
			if (GC.getBuildingInfo((BuildingTypes) iI).isReplacesBuildingClass(GC.getBuildingInfo(eBuilding).getBuildingClassType()))
			{
				if (isHasBuildingClass(iI))
				{
					return false;
				}
			}
		}
Does not work. Any ideas why?
 
Ahh... I see. So it is impossible for units to get two race? Neat.

Well, that's true, but it's not what I meant. The promotion is being stored to a variable, not added to a unit; Since he is setting the variable equal to the promotion instead of adding it (=, rather than +=), it only stores one promotion. This means that it'll store SvartElf for a miniscule amount of time before it's overwritten by Dwarven.

Ok, got another problem ;)

I am trying to add building replacement mechnics - so i.e. palisade gets removed after building walls and can't be build if walls are in the city. I had ti working in python for a long time, but I plan to expand this a bit so dll would be great way to do it.

So, I have added a tag ReplacesBuildingClass. It works fine for the removal part, but I can't find a way to make it block rebuilding of the building.

The code was added just below BuildingClassNeededInCity part of CanConstruct in CvCity.cpp
Code:
		for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
		{
			if (GC.getBuildingInfo((BuildingTypes) iI).isReplacesBuildingClass(GC.getBuildingInfo(eBuilding).getBuildingClassType()))
			{
				if (isHasBuildingClass(iI))
				{
					return false;
				}
			}
		}
Does not work. Any ideas why?

That looks like it should work... Maybe you're missing a (BuildingClassTypes)?
 
It is good to take a break sometimes ;)
Valkrionn, your comment set me on the right course, and then, while taking a shower, I got it :D

The code was wrong as I should ask about building types, not building class types (as replacing is part of building info)
I am posting this as a lesson for other ;)

Code:
		for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
		{
			if (GC.getBuildingInfo((BuildingTypes)iI).isReplacesBuildingClass(GC.getBuildingInfo(eBuilding).getBuildingClassType()))
			{
				if (isHasBuildingClass(GC.getBuildingInfo((BuildingTypes) iI).getBuildingClassType()))
				{
					return false;
				}
			}
		}
This works.
 
Edit: I found the answer. It's by using python in the CvRandomEventInterface.py that the AI choses random event options for computer players.
 
Let's say I want to modify a specific, already existing FfH event to NOT occur for a specific civilization, but still be possible for all others. (Like Hyborem never even having the possibility of firing a specific event.)
Would that be done via python or XML? And what section of code, please?
 
You need a <PythonCanDo> on the EventTrigger.

Python would be something like this:

Code:
def canTriggerEvent(argsList):
	kTriggeredData = argsList[0]
	iPlayer = kTriggeredData.ePlayer
	pPlayer = gc.getPlayer(iPlayer)
	if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_X'):
		return False
	return True
 
You need a <PythonCanDo> on the EventTrigger.

Python would be something like this:

Code:
def canTriggerEvent(argsList):
	kTriggeredData = argsList[0]
	iPlayer = kTriggeredData.ePlayer
	pPlayer = gc.getPlayer(iPlayer)
	if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_X'):
		return False
	return True

Perfect, thanks.
 
Back
Top Bottom