Mod-Modders Guide to Fall Further

EDIT: nevermind, was being overwritten by another module >_>
 
Dear FF Team,

Would you mind publishing the CvTeam.setForceRevealedBonus function to be called from python ?
Even better would be a function which could force the bonus to be revealed for one plot only, but simply publishing this function would be good and easy I think (good for me and easy for you :p)

Thanks in advance !
 
I have managed to add a new unit and unit class modularly, including having the new unit spawn with a new item. Now, if I want him to be, say, similar to Orthus or one of the other Barb/Animal heroes and spawn into the map upon certain preconditions, am I going beyond the scope of modular XML and moving into Python? If so, can Odalrick's modular Python be used for this?
 
Margalard and the others are spawned by random events, there should be no need for python if the conditions are something that can be expressed in those terms. As far as I know, only Orthus is spawned by python alone.

When it comes to actually spawning the unit, I know Margalard uses python to do that, I think so that Margalard is assigned to the animal player. I know units can be spawned without python, but I don't know what the limitations are.

If you do need python for anything, modular python should allow you to do that.
 
So if I did want to assign him to the animal player, like Margalard. I could duplicate the Python used to spawn Margalard, add it using your modular python and do all the rest in XML?
 
You could still use pure Modular XML for it. Make an event which happens at the prereqs you want for the spawn to occur, and the event creates a unique improvement (even if it just APPEARS to be some other improvement, like City Ruins) which can spawn 1 and only 1 copy of your new unit in the course of the game, for the appropriate Barbarian Civ.

You could also be mean and make it only able to spawn one of the unit AT A TIME, so that until someone finds and destroys the improvement he is ALWAYS alive (reborn by random checks shortly after death)
 
I've been converting the current version of my Frozen civilization from base Fall from Heaven 2 to a Fall Further module. I'm having some trouble, however.

1. Below is part of my Frozen_CIV4ProjectInfos.xml (the other parts, all I do is remove the Illians as a prereq from the Illian rituals, allowing both the Frozen and Illians to build them via python):

Code:
		<ProjectInfo>
			<Type>PROJECT_LIBERATION</Type>
			<Description>TXT_KEY_PROJECT_LIBERATION</Description>
			<Civilopedia>TXT_KEY_PROJECT_LIBERATION_PEDIA</Civilopedia>
			<Strategy>TXT_KEY_PROJECT_LIBERATION_STRATEGY</Strategy>
			<TechPrereq>TECH_ELEMENTALISM</TechPrereq>
			<iMaxGlobalInstances>1</iMaxGlobalInstances>
			<iCost>600</iCost>
			<Button>Modules\NormalModules\Frozen\Frozen\Winter Tech 1.dds</Button>
			<BonusProductionModifiers>
				<BonusProductionModifier>
					<BonusType>BONUS_MANA_ICE</BonusType>
					<iProductonModifier>100</iProductonModifier>
				</BonusProductionModifier>
			</BonusProductionModifiers>
			<iAIWeight>100</iAIWeight>
		</ProjectInfo>

However, when I start up Fall Further with my module included, the pedia claims that Liberation is required to create all other rituals. I don't think there's anything wrong here... is there?

2. Similarly, this is my Frozen_CIV4TechInfos.xml:

Code:
		<TechInfo>
			<Type>TECH_WINTER_TECH</Type>
			<Description>TXT_KEY_TECH_WINTER_TECH</Description>
			<Civilopedia>TXT_KEY_TECH_WINTER_TECH_PEDIA</Civilopedia>
			<Advisor>ADVISOR_RELIGION</Advisor>
			<iCost>-1</iCost>
			<iAdvancedStartCost>-1</iAdvancedStartCost>
			<Era>ERA_ANCIENT</Era>
			<iAsset>40</iAsset>
			<iGridX>1</iGridX>
			<iGridY>21</iGridY>
			<Flavors>
				<Flavor>
					<FlavorType>FLAVOR_GROWTH</FlavorType>
					<iFlavor>10</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_PRODUCTION</FlavorType>
					<iFlavor>20</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_RELIGION</FlavorType>
					<iFlavor>70</iFlavor>
				</Flavor>
			</Flavors>
			<Quote>TXT_KEY_TECH_WINTER_TECH_PEDIA</Quote>
			<Sound>AS2D_TECH_DING</Sound>
			<SoundMP>AS2D_TECH_DING</SoundMP>
			<Button>Modules\NormalModules\Frozen\Frozen\Winter Tech 3.dds</Button>
                </TechInfo>

The pedia claims that it gives a "+ 3014702 :science:" and "+ 3014702% :science:" cost to every other tech. Again, I don't think I did anything wrong here... but the game seems to think otherwise.
 
Ok, so I got a little further and hit another wall. I have created a unique improvement to be spawned via event that can only spawn only one of my chosen unit, thanks Xienwolf.

However, when it comes to creating the event to place the improvement, not only am I unable to get any message box popups displaying my event choices, but every event in the game seems to have the results for my new event as every possible outcome. The odd thing is, if I delete the second entry under <Event>EVENT_BLAH_2</Event> in the trigger and its entry in Test_CIV4EventInfos.xml, all the existing events go back to normal.
 
Tech issue someone else already found and reported, probably similar on the Project issue. Just some flaws in the new modular code setup which I have to polish up this next week. Most likely the same issue on the events, but that one at least I have a chance to hope that WoC solved it themselves. Read about them having some sort of issue with events earlier.
 
Dear FF Team,

Would you mind publishing the CvTeam.setForceRevealedBonus function to be called from python ?
Even better would be a function which could force the bonus to be revealed for one plot only, but simply publishing this function would be good and easy I think (good for me and easy for you :p)

Thanks in advance !

Quoting myself hoping for a yes :blush:
 
And now I'm having another problem. This is the code I added to CvEventManager.py's onProjectBuilt, a copied version of the Fall from Heaven 2 Infernal code.

Spoiler :
Code:
		if iProjectType == gc.getInfoTypeForString('PROJECT_LIBERATION'):
			iFrozenPlayer = cf.getOpenPlayer()
			pBestPlot = -1
			iBestPlot = -1
			for i in range (CyMap().numPlots()):
				pPlot = CyMap().plotByIndex(i)
				iPlot = -1
				if pPlot.isWater() == False:
					if pPlot.getNumUnits() == 0:
						if pPlot.isCity() == False:
							if pPlot.isImpassable() == False:
								iPlot = CyGame().getSorenRandNum(500, "Place Taranis")
								iPlot = iPlot + (pPlot.area().getNumTiles() * 2)
								iPlot = iPlot + (pPlot.area().getNumUnownedTiles() * 10)
								if pPlot.isOwned() == False:
									iPlot = iPlot + 500
								if pPlot.getOwner() == iPlayer:
									iPlot = iPlot + 200
				if iPlot > iBestPlot:
					iBestPlot = iPlot
					pBestPlot = pPlot
			if (iFrozenPlayer != -1 and pBestPlot != -1):
				CyGame().addPlayerAdvanced(iFrozenPlayer, -1, gc.getInfoTypeForString('LEADER_TARANIS'), gc.getInfoTypeForString('CIVILIZATION_FROZEN'))
				iFounderTeam = gc.getPlayer(iPlayer).getTeam()
				eFounderTeam = gc.getTeam(gc.getPlayer(iPlayer).getTeam())
				iFrozenTeam = gc.getPlayer(iFrozenPlayer).getTeam()
				eFrozenTeam = gc.getTeam(iFrozenTeam)
				for iTech in range(gc.getNumTechInfos()):
					if eFounderTeam.isHasTech(iTech):
						eFrozenTeam.setHasTech(iTech, true, iFrozenPlayer, true, false)
				eFounderTeam.signOpenBorders(iFounderTeam)
				eFrozenTeam.signOpenBorders(iFrozenTeam)
				pFrozenPlayer = gc.getPlayer(iFrozenPlayer)
				pFrozenPlayer.AI_changeAttitudeExtra(iPlayer,4)
				eFrozenTeam.setHasTech(gc.getInfoTypeForString('TECH_WINTER_TECH'), true, iFrozenPlayer, true, false)
				newUnit1 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ICE_GOLEM'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit1.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit2 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ICE_GOLEM'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit2.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit3 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_CHAMPION'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit3.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), true)
				newUnit3.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit4 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_CHAMPION'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit4.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), true)
				newUnit4.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit5 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_WORKER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit5.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				newUnit6 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ADEPT'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit6.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit7 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit8 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit9 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit10 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_SETTLER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit10.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STARTING_SETTLER'), true)
				newUnit10.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				newUnit11 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_SETTLER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit11.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STARTING_SETTLER'), true)
				newUnit11.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				if gc.getPlayer(iPlayer).isHuman():
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON)
					popupInfo.setText(CyTranslator().getText("TXT_KEY_POPUP_CONTROL_FROZEN",()))
					popupInfo.setData1(iPlayer)
					popupInfo.setData2(iFrozenPlayer)
					popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_POPUP_YES", ()), "")
					popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_POPUP_NO", ()), "")
					popupInfo.setOnClickedPythonCallback("reassignPlayer")
					popupInfo.addPopup(iPlayer)[/SPOILER]

When I complete Liberation in-game using a test (by setting the cost of the ritual to 1 hammer and giving myself the prereq technology) and switch to the Frozen, I can't see any of the plots I'm on. As I explore with some of my starting units, I find that I can't see many other plots as well. (some seem to be randomly revealed, others aren't). Yet, I still have line of sight on my old civilization's plots, although I cannot see my old capital or any units. (There's no fog of war). Have I done something wrong?

EDIT: A test as the Infernals revealed similar issues. I could not see any terrain that the civ who summoned the Infernals had not revealed already, and as I explored several plots were not revealed...
 
And now I'm having another problem. This is the code I added to CvEventManager.py's onProjectBuilt, a copied version of the Fall from Heaven 2 Infernal code.

Spoiler :
Code:
		if iProjectType == gc.getInfoTypeForString('PROJECT_LIBERATION'):
			iFrozenPlayer = cf.getOpenPlayer()
			pBestPlot = -1
			iBestPlot = -1
			for i in range (CyMap().numPlots()):
				pPlot = CyMap().plotByIndex(i)
				iPlot = -1
				if pPlot.isWater() == False:
					if pPlot.getNumUnits() == 0:
						if pPlot.isCity() == False:
							if pPlot.isImpassable() == False:
								iPlot = CyGame().getSorenRandNum(500, "Place Taranis")
								iPlot = iPlot + (pPlot.area().getNumTiles() * 2)
								iPlot = iPlot + (pPlot.area().getNumUnownedTiles() * 10)
								if pPlot.isOwned() == False:
									iPlot = iPlot + 500
								if pPlot.getOwner() == iPlayer:
									iPlot = iPlot + 200
				if iPlot > iBestPlot:
					iBestPlot = iPlot
					pBestPlot = pPlot
			if (iFrozenPlayer != -1 and pBestPlot != -1):
				CyGame().addPlayerAdvanced(iFrozenPlayer, -1, gc.getInfoTypeForString('LEADER_TARANIS'), gc.getInfoTypeForString('CIVILIZATION_FROZEN'))
				iFounderTeam = gc.getPlayer(iPlayer).getTeam()
				eFounderTeam = gc.getTeam(gc.getPlayer(iPlayer).getTeam())
				iFrozenTeam = gc.getPlayer(iFrozenPlayer).getTeam()
				eFrozenTeam = gc.getTeam(iFrozenTeam)
				for iTech in range(gc.getNumTechInfos()):
					if eFounderTeam.isHasTech(iTech):
						eFrozenTeam.setHasTech(iTech, true, iFrozenPlayer, true, false)
				eFounderTeam.signOpenBorders(iFounderTeam)
				eFrozenTeam.signOpenBorders(iFrozenTeam)
				pFrozenPlayer = gc.getPlayer(iFrozenPlayer)
				pFrozenPlayer.AI_changeAttitudeExtra(iPlayer,4)
				eFrozenTeam.setHasTech(gc.getInfoTypeForString('TECH_WINTER_TECH'), true, iFrozenPlayer, true, false)
				newUnit1 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ICE_GOLEM'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit1.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit2 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ICE_GOLEM'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit2.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit3 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_CHAMPION'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit3.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), true)
				newUnit3.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit4 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_CHAMPION'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit4.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), true)
				newUnit4.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit5 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_WORKER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit5.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				newUnit6 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_ADEPT'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit6.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MOBILITY1'), true)
				newUnit7 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit8 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit9 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_FROZEN_SOUL'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit10 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_SETTLER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit10.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STARTING_SETTLER'), true)
				newUnit10.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				newUnit11 = pFrozenPlayer.initUnit(gc.getInfoTypeForString('UNIT_SETTLER'), pBestPlot.getX(), pBestPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				newUnit11.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STARTING_SETTLER'), true)
				newUnit11.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), true)
				if gc.getPlayer(iPlayer).isHuman():
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON)
					popupInfo.setText(CyTranslator().getText("TXT_KEY_POPUP_CONTROL_FROZEN",()))
					popupInfo.setData1(iPlayer)
					popupInfo.setData2(iFrozenPlayer)
					popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_POPUP_YES", ()), "")
					popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_POPUP_NO", ()), "")
					popupInfo.setOnClickedPythonCallback("reassignPlayer")
					popupInfo.addPopup(iPlayer)[/SPOILER]

When I complete Liberation in-game using a test (by setting the cost of the ritual to 1 hammer and giving myself the prereq technology) and switch to the Frozen, I can't see any of the plots I'm on. As I explore with some of my starting units, I find that I can't see many other plots as well. (some seem to be randomly revealed, others aren't). Yet, I still have line of sight on my old civilization's plots, although I cannot see my old capital or any units. (There's no fog of war). Have I done something wrong?

EDIT: A test as the Infernals revealed similar issues. I could not see any terrain that the civ who summoned the Infernals had not revealed already, and as I explored several plots were not revealed...
Spoiler :


I guess my post was missed since xienwolf was posting while I was posting. Just bumping this a little.
 
Hey,

Does someone knows why the python function onBeginPlayerTurn is not called before the first turn ?
I want to do something before the player starts playing, but it is called only from turn 2.
 
You need to run it every turn? If not, then use onGameStart.

If yes, then I don't know why it does not run before turn 2. Seems like it ought to start on turn 1.
 
TC01: Saw it, but wasn't able to work on it much at all, so hoped for some other python folk to respond before I got back to the computer.

Never used the addPlayerAdvanced setup so far, but everything looks decent, but I don't have the infernal code up to ensure that you copied over everything which looks important from there.


To debug things, I would say cut your code out and paste it somewhere else so it isn't lost, then pluck the infernal code and put the EXACT code into this spot, only change being trigger from this project instead of from a tech. See if you get the same issue (if you do, then there is some issue with triggering from projects instead of techs or buildings, which would be strange). If you do not, then change ONLY the Civ and Leader (but not the variable names they are stored in) and see again if it works properly. Should that be the case, then it is possible that somewhere you typo'd when renaming a variable, or just missed one of the variables which needed renamed.
 
I copied the Infernal summoing code and changed it to check for a project.. Got the same thing. I also attached a screenshot. In the top of the screen, there's all black, with the Infernal city of Dis, the Infernal starting units, and a few resources. In the bottom of the screen, there's a red cultural border for my old civ, the Calabim, and all terrain revealed around it, but with no units or cities placed there.

Tying it to a project works fine in regular Fall from Heaven 2 (I just copied my code for this from the FFH 2 version of my civ)... is this a Fall Further bug of some sort?
 
And does it change anything if you save and then reload the game?

After reloading, everything's fine- my old civ isn't on the map, and I can see everything I'm supposed to.

Is this just a graphical problem on my computer?
 
Back
Top Bottom