A little modding help

DharmaMcLaren

Warlord
Joined
Dec 18, 2007
Messages
213
Location
Scotland
I'm modding a new civ into FfH (which I may or may not release - at least, I won't unless I can get an image I have permission to use [Cuteunit?]). I've got the civ all set up fine, their unique unit (a panther replacement for the scout which is cheaper and starts hidden, has 4 defensive strength but can't attack) is working, and their unique building, a replacement for the grove, is in the game and working. However, I want to add something to the unique building so that when a unit is produced in the city that has the grove, there's a chance that an additional animal unit will be produced. I've looked through all the XML and can't begin to guess what might be able to do this - I was specifically looking at entries for the CoE Warrens and the Sheaim Planar Gate. Could anyone offer a bit of guidance?

Edit: Also, how would one make a new leader trait to give a new free promotion giving +1 defensive strength and the Subdue Animals promotion to all units?
 
I think to get the chance of an extra unit you would have to use python and for your edit go to the civiliztions xml folder and go to civ4traitinfos.xml and I think you would have to split that trait into two different ones to get it to work how you want. Hope this helped :)
 
I could just make a promotion combining Subdue Animals and +1 def, I suppose. Python, huh... Oh well, here goes nothing.
 
The python for the Warrens building is in cvEventManager.py under "def onUnitBuilt".

Assuming you want to do the same thing, more or less, where the panther is only created if the unit being built is a living non-hero unit, you'd want to copy that block of code and paste it directly below itself. Make sure the spacing stays the same! Python uses tabs to indicate code blocks. Change "BUILDING_WARRENS" to the name of your unique grove (make sure you don't just change it to BUILDING_GROVE, or the code will trigger for all players). Then, in the very last line of the copied code, the one that starts newUnit = pPlayer.initUnit, you'll want to change "unit.getUnitType()" to "gc.getInfoTypeForString('UNIT_PANTHER')", replacing UNIT_PANTHER with whatever your panther unit is called.

So, assuming I haven't screwed anything up, your new block of code (which should be pasted directly below the Warrens code) should look like this:

Code:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_GROVE_UNIQUE')) > 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(gc.getInfoTypeForString('UNIT_PANTHER'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)

Of course you need to replace BUILDING_GROVE_UNIQUE with whatever your unique grove is called, and UNIT_PANTHER with whatever your panther unit is called. If you wanted to change the code so that it will trigger even on the creation of hero and national units, you'd just have to cut out the relavent if statements and change the spacing to match. That would look something like this:

Code:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_GROVE_UNIQUE')) > 0:
			if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
				if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
					newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PANTHER'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)

Note that just like the Warrens, this will trigger even on the creation of Workers and Settlers.
 
It isn't hard to make a trait give multiple promotions to multiple unitcombats, usnig only xml. It won't apply to al units (not great people, settlers, workers, workboats, loki, etc), but it will be given to most of them. You can basically copy heroic defense promotion for your new promotion, but with different requirements probably, and apply both promos. Just create a new trait (and give it to some leader) with this at the end:
Code:
<FreePromotions>
	<FreePromotion>
		<PromotionType>PROMOTION_SUBDUE_ANIMAL</PromotionType>
		<bFreePromotion>1</bFreePromotion>
	</FreePromotion>
	<FreePromotion>
		<PromotionType>PROMOTION_NEW_PROMOTION</PromotionType>
		<bFreePromotion>1</bFreePromotion>
	</FreePromotion>
</FreePromotions>
<FreePromotionUnitCombats>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_MELEE</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_MOUNTED</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_ARCHER</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_NAVAL</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_DISCIPLE</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_SIEGE</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_RECON</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_ANIMAL</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
	<FreePromotionUnitCombat>
		<UnitCombatType>UNITCOMBAT_BEAST</UnitCombatType>
		<bFreePromotionUnitCombat>1</bFreePromotionUnitCombat>
	</FreePromotionUnitCombat>
</FreePromotionUnitCombats>
 
Note that giving Subdue Animal to Naval units would make your civ the only civ in the game that could easily capture Sea Serpents and Giant Turtles. :)
 
Thanks for all the advice with this. What I want to do with the animal-spawning building is have a 6% chance for a bear with every unit produced, a 5% chance for a tiger, a 5% chance for a panther, and a 4% chance for a gorilla.

This is what I (with my total lack of Python knowledge) came up with:

Code:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_VILLALFAR_GROVE')) > 0:
                        if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
				if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
                                        if CyGame().getSorenRandNum(100, "Bob") <= 5, >0:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_PANTHER')
                                        if CyGame().getSorenRandNum(100, "Bob") <= 10, >5:
                                                 newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_TIGER')
                                        if CyGame().getSorenRandNum(100, "Bob") <= 14, >10:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_GORILLA')
                                        if CyGame().getSorenRandNum(100, "Bob") <= 20, >14:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_BEAR')

Is this a good base? Does anyone know what's wrong with it? (I imagine that's a resounding "Yes" :blush: )

As for the leader trait, I COULD just make it give Subdue Animal and Heroic Defense 1, but I'd like it to go to ALL units - workers would be able to capture animals if attacked by them (if they won). The whole race are sort of FoL fanatics who place huge importance on attunement with nature, so I'd like it to go to everything except naval units and siege units (I'm pretty sure they can't build siege units anyway - I used the Ljosalfar as a base). I think I need to use Python to give the promotion the animal-taming qualities of Subdue Animal, which is what I'm going to try to tackle next.
 
Can you do statements like x <= 20, >14 instead of typing out x <= 20 and x> 14? If so, then I've been doing way too much typing...
 
Hah, I have absolutely no idea - I just guessed how to do those because there was no example in the rest of the file. >.<

I'll try changing them all to ands... :P

Edit: Predictably, still doesn't work.
 
I'm not actually sure the "," don't work, but would like to know if they do. You do realize that if you use "and" you will need to repeat the left side, right?

I think I see the real problem is in the .initUnit(), which does not have enough parameters in any of the lines you wrote. it should be like "pPlayer.initUnit(gc.getInfoTypeForString('UNIT_WARRIOR'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)". The first parameter is the type of unit to to initialize, the second is the x coordinate, the third the y coordinate, the forth the ai for the unit (I think I've heard that only only no_unitAI works for some reason), and the direction the unit will face (I don't think that was necessary until BtS)
 
All right, here's the new code:

Code:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_VILLALFAR_GROVE')) > 0:
                        if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
				if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
                                        if CyGame().getSorenRandNum(100, "Bob") <= 5 and CyGame().getSorenRandNum(100, "Bob") >0:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_PANTHER'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 10 and CyGame().getSorenRandNum(100, "Bob") >5:
                                                 newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_TIGER'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 15 and  CyGame().getSorenRandNum(100, "Bob") >10:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_WOLF'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 20 and CyGame().getSorenRandNum(100, "Bob") >15:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_BEAR'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)

But it's still not working. The good news is that I just used Subdue Animals and a new promotion to get the leader trait right, and I've got their hero in the game now.
 
In your case there is no caster (this isn't a spell), so caster.getX() and caster.getY() make no sense.

I think that using either city.getX() and city.getY() or unit.getX() and unit.getY() might fix it. (assuming this code is put in the same place as warrens, these would be the same thing)


Also, there is no panther unit in FfH anymore (unless you added it back)
 
It works!... In a way. Now I get a Crown of Akharien for about 50% of units (rather than an animal for the intended 20%). It's a little bizarre.

Code:
		if city.getNumRealBuilding(gc.getInfoTypeForString('BUILDING_VILLALFAR_GROVE')) > 0:
                        if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
				if unit.getUnitCombatType() != gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
                                        if CyGame().getSorenRandNum(100, "Bob") <= 3 and CyGame().getSorenRandNum(100, "Bob") >0:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_GORILLA'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 8 and CyGame().getSorenRandNum(100, "Bob") >3:
                                                 newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_TIGER'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 15 and  CyGame().getSorenRandNum(100, "Bob") >8:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_WOLF'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
                                        if CyGame().getSorenRandNum(100, "Bob") <= 20 and CyGame().getSorenRandNum(100, "Bob") >15:
                                                newUnit = pPlayer.initUnit(unit.getUnitType() == gc.getInfoTypeForString('UNIT_BEAR'), city.getX(), city.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)

I don't really see how anything in there could be mistakened for a Crown of Akharien...
 
That mistake is quite amusing, and it confused me at first as to how it was possible. Then I noticed one critical error that I somehow overlooked before (It seems like I find something new every time I read this code)

This time, I noticed that you do not define the unit you want to be give, you check to see if the unit you just built is the same type of unit. The "unit.getUnitType() == gc.getInfoTypeForString('UNIT_GORILLA')" returns a boolean value of false, which can also be read as a 0.


I knew from the BtS pytho API that unit types are, in fact, simple integers, but wasn't sure what kind of number it would be looking for. To find the number associated with the string "xyz" it one uses the call gc.getInfoTypeForString('xyz'). Now I realize that all this does is return the index of where that string is found in a list of units, which is taken directly from CIV4UnitInfos.xml. Since the game can read a value of false as a 0, it looked at index 0 in this list, and so initialized the first unit in CIV4UnitInfos.xml: the crown of Akarien equipment.

If you just built the same type of unit you were trying to initialize (not that these animals are buildable), it would return a true. This would be read as the integer 1, and so it would give you the unit found at index 1 of the list, or second in CIV4UnitInfos.xml, which is the Dragon's Horde equipment.

Case solved.


To fix this bug, replace unit.getUnitType() == gc.getInfoTypeForString('UNIT_GORILLA') with simply gc.getInfoTypeForString('UNIT_GORILLA'), and so on for the other units.
 
Thank you so much, Magister! You've been awfully patient with me. It works like a charm now, and my knowledge of Python is enhanced. I might be able to make a UB without help now. >.<
Now I've just got to think of and make a world spell, and this'll be ready for release. I could maybe reskin the Ljosalfar models that I'm currently using, too. And I've got a few Civilopedia entries to write...
Anyway, thanks muchly! 'Twas really nice of you to help, and it's much appreciated! :D
 
You are welcome. It isn't like I anything else to do (except for a bunch of school work that I should have done by now, but don't feel like starting)


You do not need to do anything with python to make a promotion allow animal taming, just change the <CaptureUnitCombat>NONE</CaptureUnitCombat> to <CaptureUnitCombat>UNITCOMBAT_ANIMAL</CaptureUnitCombat> in your new promotion.

If you still want to give the promotion to all the units you build (including those with no unitcombat, like workers), just put this in the same place as you put the other piece of Python coding:
Code:
		if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_NEW_CIV'):
			if unit.isAlive():
				unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_NEW_PROMOTION'), True)
but change CIVILIZATION_NEW_CIV to your civ's name and PROMOTION_NEW_PROMOTION to your promotion's name.

The if unit.isAlive() part isn't necessary, itmeans it only applies if it is a living unit, so it won't apply to naval units, siege units, or undead/demon/angels/elementals. Animal handling just doesn't seem appropriate for any of those (well, possibly angels of nature UUs or elementls like treants, but it is easier to ignore that). You might also want to replace the 2 if statements making unitcombat_siege and unitcombat_naval not eligible with one using unit.isAlive() instead.

Note that this will only give the promotion to units you build, not those you start with or gain though events, goody huts, summons, etc. (you could make the promotion apply itself a <PromotionSummonPerk>, if you wanted your summons to have the promotion too)

If you want, you could instead stick with the trait based approach and give your workers, settlers, etc, a unitcombat. You could pick one of the existing ones, like UNITCOMBAT_RECON, or create a new one altogether (I've never done this, but it doesn't look hard. It would just involve adding a couple of lines to to the CIV4UnitCombatInfos.xml in the Basicinfos folder). Note that if you are changing the main unit then you may be giving some free promotions/xp/ability to gain promotions to your rivals units, and if you are creating a UU so as not to give them these boni then you might as well just give yourself a UU that starts with the promotion.
 
Ta very much! :D :D :D

If you're ever stuck for something to do again, the model for their palace isn't working. It's the Jade College model here, and I've used JadeCollege.nif as the model, but only the treetops show in colour, the rest is pink. Think you can solve that one, too? :P
 
Sorry, but I really don't know anything when it comes to making the models/skins/animations/effects/graphics/icons/art for the game. It sounds like you probably know more than me in that area.

My modding knowledge is limited to xml/python. (although when I have the time, maybe over the summer, I may try to teach myself C++ too. It doesn't look that hard, when looking at the code snippets I've seen in the forum instead of the nonsensical complied form.) I typically just refer to preexisting art for all my new buildings/wonders/units/heroes, and have never added custom art except for the female Sidar leader that Cute Unit convinced me to add, since I was provided with the files. You might actually be able to help me with the graphical parts of my modmod more than I could help you. I probably won't try anything fancy at least in the short term, but buttons for new promotions and graphics for new resources would be nice.
 
Is the shape all correct, just the color is messed up?

MC: Python is VERY similar to C++, so if you are comfy with Python it won't take you too long to get acquainted with C++. You can look through the SDK pre-compiled in the Beyond the Sword\CvGameCoreDLL folder.
 
Back
Top Bottom