The Warrens and copies of its function.

dotdotdot

Chieftain
Joined
Jul 21, 2007
Messages
11
I absolutely love FfH 2. It's absolutely mind blowing. I've started to tinker with Python and duplicated the Warrens structure on multiple other buildings, allowing cities to build four units a turn.

When I try to replicate this on other mods, however, I can only get two units constructed at the same time. Was there some code that was removed in FfH2's development or would I have to ask someone else about that limit?
 
What did you do exactly? Seeing your python modifications (even an excerpt) would greatly help others to help you. I'm confident enough to say that all lies here in the python. Especially if you managed to build two units instead of one; it means it's working somehow, if not like you would want. Anyway, your code would be helpful :)
 
The original code in FfH2 is under the CvEventManager.py

PHP:
def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())
		pPlayer = gc.getPlayer(unit.getOwner())

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_WARRENS')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if (not self.__LOG_UNITBUILD):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))

What I did for FfH2 was copy that a couple of times and apply it to these buildings:

PHP:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_TRAINING_YARD')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_SCULPTORS_STUDIO')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)


		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_ARENA')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_FORGE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_DWARVEN_SMITHY')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_ARCHERY_RANGE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_STABLE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_STABLE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDINGCLASS_DEMONIC_CITIZENS')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)


My main goal is to copy this with the Forge, Steel Mill, Factory, and Assembly Plant in Rise of Mankind 2. Since I want ships and such to be included, I took out the two lines that excluded siege units and ships. I also took out the world unit line because they don't exist in RoM2.

PHP:
umRealBuilding(gc.getInfoTypeForString('BUILDING_FACTORY')) > 0:
				if isNationalUnitClass(unit.getUnitClassType()) == False:	    
							newUnit1 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)
							newUnit2 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

When I first tried it, one factory enabled all cities to build two units at a time. Then I realized that's because RoM's onUnitBuilt didn't have pPlayer = gc.getPlayer(unit.getOwner())

After that, though, I couldn't figure out how to make cities build more units at a time...
 
The original code in FfH2 is under the CvEventManager.py

PHP:
def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())
		pPlayer = gc.getPlayer(unit.getOwner())

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_WARRENS')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if (not self.__LOG_UNITBUILD):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))

What I did for FfH2 was copy that a couple of times and apply it to these buildings:

PHP:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_TRAINING_YARD')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_SCULPTORS_STUDIO')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)


		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_ARENA')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_FORGE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_DWARVEN_SMITHY')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_ARCHERY_RANGE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_STABLE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_STABLE')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDINGCLASS_DEMONIC_CITIZENS')) > 0:
			if isWorldUnitClass(unit.getUnitClassType()) == False:
				if isNationalUnitClass(unit.getUnitClassType()) == False:
					if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
						if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)


My main goal is to copy this with the Forge, Steel Mill, Factory, and Assembly Plant in Rise of Mankind 2. Since I want ships and such to be included, I took out the two lines that excluded siege units and ships. I also took out the world unit line because they don't exist in RoM2.

PHP:
umRealBuilding(gc.getInfoTypeForString('BUILDING_FACTORY')) > 0:
				if isNationalUnitClass(unit.getUnitClassType()) == False:	    
							newUnit1 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)
							newUnit2 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

When I first tried it, one factory enabled all cities to build two units at a time. Then I realized that's because RoM's onUnitBuilt didn't have pPlayer = gc.getPlayer(unit.getOwner())

After that, though, I couldn't figure out how to make cities build more units at a time...
In the last bit, you defined newUnit1 and newUnit2 but only used newUnit in city.applyBuildEffects(). Try changing them to their corresponding variable (newUnit1 and newUnit2). I wonder if you can just leave one newUnit and use two city.apply...
Code:
if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_FACTORY')) > 0:
				if isNationalUnitClass(unit.getUnitClassType()) == False:	    
							newUnit = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)
							city.applyBuildEffects(newUnit)
Keep an eye on the indentation too. I can't really see there due to the forum indenting but I'm not sure it's good.
 
The indentation should be good. I've check it in IDLE and it spawns that second unit...

It could be something in another python file and I'll look through RoM and FfH2 to see if there are any basic differences that could interfere with the other spawns. Hopefully this isn't because FfH2has completely new set of functions for its features.

What I may end up doing is to try creating a "random event" that triggers whenever a city with one of the buildings trains something, but I want to tinker with this for just a few more days.

Thank you for the help.
 
Code:
umRealBuilding(gc.getInfoTypeForString('BUILDING_FACTORY')) > 0:
				if isNationalUnitClass(unit.getUnitClassType()) == False:	    
							newUnit1 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)
							newUnit2 = pPlayer.initUnit(unit.getUnitType(), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
							city.applyBuildEffects(newUnit)

When I first tried it, one factory enabled all cities to build two units at a time. Then I realized that's because RoM's onUnitBuilt didn't have pPlayer = gc.getPlayer(unit.getOwner())

After that, though, I couldn't figure out how to make cities build more units at a time...

The code is a bit trimmed, but:

I'm guessing you want a Factory to build three units instead of one. You get two, but the copy doesn't get the experience or free promotions it should.

That's because you haven't got any variable called newunit in the call city.applyBuildEffects(newUnit), you get an exception(*) and nothing more happens.

Remove the numbers from the newUnit1 and newUnit2 names. You don't need to refer to them later anyway.


* For some unfathomable reason Firaxis has decided that exceptions should be silently ignored by default. Look in your civilization ini file for an option called something like HidePythonExceptionsForNoGoodReason = 1, change the number to 0. That will give you nice messages whenever you make tiny mistakes like this.
 
Wouldn't it be easier to count the number of unit doubling buildings in a variable isomething and then use a looping newunitisomething function for the amount of buildings you have instead of checking each individual building.
Check out the Henchmen code in the explorelairbigbad function in Customfunctions.py for a similar example.

My guess is that the problem is that you always use newunit instead of different names (newunit1, newunit2 etc), so the function checks if he should spawn the same unit over and over again.
 
Thing is, I want the same unit to be spawned over again. I'll look at the files you suggested, but my main problem is that what works in FfH2 isn't working in another mod.

Sorry if I wasn't clear on this, but the bonus applications aren't the problem.
My problem is that I'll only get two units which are the original and one copy.

Thank you for your help, I'll start acting on your suggestions.

Edit: I'm a dumba**...

I see what you're saying, odalrick. The city.applybuildEffects was like a brick wall...Once I get rid of it, the code functions as I want it to in terms of spawning the correct number of units. Thank you all for your help.
 
I suspect you are getting a python error when you try to copy this code into other mods and thats why the function stops after the first unit is created. I would make sure python debugging is on so you can see if any errors are occuring.

In particular applyBuildEffects() is a FfH only function. We created it because in normal civ4 all the special stuff a unit gets when he's built (bones xp or promotion from buildings, etc) are in the function that produces the unit. Since we wanted to give all those things outside of the normal unit production function we created a unique function just to apply those effects. I would just remove the applyBuildEffects() line from your code when you put it in other mods, though dont be surprised when they dont end up with building bonuses.
 
Having that many units in Rise of Mankind is just ... scary o.O
 
Top Bottom