Mod-Modders Guide to Fall Further

Here it is :

Spoiler :

Code:
<Civ4TerrainInfos xmlns="x-schema:CIV4TerrainSchema.xml">
	<TerrainInfos>
		<TerrainInfo>
			<Type>TERRAIN_RAW</Type>
			<Description>TXT_KEY_TERRAIN_RAW</Description>
			<Civilopedia>TXT_KEY_TERRAIN_RAW_PEDIA</Civilopedia>
			<ArtDefineTag>ART_DEF_TERRAIN_RAW</ArtDefineTag>
			<Yields>
				<iYield>-1</iYield>
				<iYield>-2</iYield>
				<iYield>-1</iYield>
			</Yields>
			<RiverYieldChange>
				<iYield>0</iYield>
				<iYield>0</iYield>
				<iYield>0</iYield>
			</RiverYieldChange>
			<HillsYieldChange/>
			<bWater>0</bWater>
			<bImpassable>0</bImpassable>
			<bFound>0</bFound>
			<bFoundCoast>0</bFoundCoast>
			<bFoundFreshWater>0</bFoundFreshWater>
			<iMovement>2</iMovement>
			<iSeeFrom>1</iSeeFrom>
			<iSeeThrough>1</iSeeThrough>
			<iBuildModifier>25</iBuildModifier>
			<iDefense>-50</iDefense>
			<Button>Art/Interface\Buttons\WorldBuilder\Terrain_Desert.dds</Button>
			<FootstepSounds>
				<FootstepSound>
					<FootstepAudioType>FOOTSTEP_AUDIO_HUMAN</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_FOOT_UNIT_SAND</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>FOOTSTEP_AUDIO_HUMAN_LOW</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_FOOT_UNIT_LOW_SAND</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>FOOTSTEP_AUDIO_ANIMAL</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_ANIMAL_FOOT_LARGE_SAND</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>FOOTSTEP_AUDIO_ANIMAL_LOW</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_ANIMAL_FOOT_LARGE_LOW_SAND</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>FOOTSTEP_AUDIO_HORSE</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_HORSE_RUN</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_WHEELS</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_CHARIOT_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_WHEELS</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_CHARIOT_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_WHEELS_2</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_WAR_CHARIOT_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_WHEELS_2</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_WAR_CHARIOT_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_TANK</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TANK_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_TANK</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TANK_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_MOD_ARMOUR</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_MOD_ARMOUR_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_MOD_ARMOUR</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_MOD_ARMOUR_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_OCEAN1</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_OCEAN_LOOP1</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_OCEAN1</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_OCEAN_END1</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_OCEAN2</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_OCEAN_LOOP1</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_OCEAN2</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_OCEAN_END2</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_DESTOYER</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_DESTROYER_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_DESTROYER</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_DESTROYER_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_IRONCLAD</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_IRONCLAD_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_IRONCLAD</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_IRONCLAD_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_TRANSPORT</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TRANSPORT_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_TRANSPORT</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TRANSPORT_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_SUBMARINE</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_SUBMARINE_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_SUBMARINE</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_SUBMARINE_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_GUNSHIP</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_GUNSHIP_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_GUNSHIP</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_GUNSHIP_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_ARTILLERY</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_ARTILLERY_RUN_LOOP</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_ARTILLERY</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_ARTILLERY_RUN_END</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>LOOPSTEP_WHEELS_3</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TREBUCHET_RUN</FootstepAudioScript>
				</FootstepSound>
				<FootstepSound>
					<FootstepAudioType>ENDSTEP_WHEELS_3</FootstepAudioType>
					<FootstepAudioScript>AS3D_UN_TREBUCHET_STOP</FootstepAudioScript>
				</FootstepSound>
			</FootstepSounds>
			<WorldSoundscapeAudioScript>ASSS_DESERT_SELECT_AMB</WorldSoundscapeAudioScript>
			<bGraphicalOnly>0</bGraphicalOnly>
			<ArtDefineTag2>ART_DEF_TERRAIN_DESERT_BM</ArtDefineTag2>
			<bNormalize>1</bNormalize>
			<iPlotCounterDown>0</iPlotCounterDown>
			<TerrainDown>NONE</TerrainDown>
			<iPlotCounterUp>9</iPlotCounterUp>
			<TerrainUp>TERRAIN_RAW</TerrainUp>
		</TerrainInfo>
	</TerrainInfos>
</Civ4TerrainInfos>


And the Art linked to it:

Spoiler :

Code:
<Civ4ArtDefines xmlns="x-schema:CIV4ArtDefinesSchema.xml">
	<TerrainArtInfos>
		<TerrainArtInfo>
			<Type>ART_DEF_TERRAIN_RAW</Type>
			<Path>Modules\NormalModules\Tears\Art\barelandblend.dds</Path>
			<Grid>Modules\NormalModules\Tears\Art\barelandgrids.dds</Grid>
			<Detail>Art/Terrain/Textures/DesertDetail.dds</Detail>
			<Button>Modules\NormalModules\Tears\Art\Buttons\Terrains\Bareland.dds</Button>
			<LayerOrder>10</LayerOrder>
			<AlphaShader>0</AlphaShader>
			<TextureBlend01>8,0</TextureBlend01>
			<TextureBlend02>1,0</TextureBlend02>
			<TextureBlend04>6,0</TextureBlend04>
			<TextureBlend08>5,0</TextureBlend08>
			<TextureBlend03>2,0</TextureBlend03>
			<TextureBlend06>10,0</TextureBlend06>
			<TextureBlend12>12,0</TextureBlend12>
			<TextureBlend09>9,0</TextureBlend09>
			<TextureBlend07>3,0</TextureBlend07>
			<TextureBlend14>14,0</TextureBlend14>
			<TextureBlend13>11,0</TextureBlend13>
			<TextureBlend11>4,0</TextureBlend11>
			<TextureBlend10>7,0</TextureBlend10>
			<TextureBlend05>13,0</TextureBlend05>
			<TextureBlend15>15,0 16,0 18,0 19,0 20,0 21,0 22,0 23,0 24,0 25,0 26,0 27,0 28,0 29,0 30,0 31,0 32,0</TextureBlend15>
		</TerrainArtInfo>
	</TerrainArtInfos>
</Civ4ArtDefines>


What it does when I add a tile in the worlbuilder is convert it from LAND to OCEAN visually.
When the terrain changes ingame through python it works fine (plot stays LAND).
 
Hrm... I would say remove the PlotCounterUp reference, upgrading to yourself is just a waste of processor time, simply let nothing happen like ice does :)

Visually it changes to Ocean, but how about what it says when you do a mouseover of the plot outside of worldbuilder?

Also, try doing this non-modular. I know that there are limitations still in art being able to be done modularly, that might be what you run into here.
 
Trying to make some transforming abilities. I have some specific questions, and some requests for more general advice.


I'm looking at the Haunt code as a base. As far as I understand, it basically creates a new unit (the haunt) and then copies over parameters from the caster

I don't see anywhere that the original unit is removed, though. But I don't recall the haunt spell leaving anything behind.

Also, the section marked in bold:

Spoiler :
Code:
def spellHaunt(caster):
	pPlayer = gc.getPlayer(caster.getOwner())
	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_HAUNT'), caster.getX(), caster.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
	[B]for i in range(gc.getNumPromotionInfos()):
		if gc.getPromotionInfo(i).isEquipment() == False:
			newUnit.setHasPromotion(i, caster.isHasPromotion(i))[/B]
	newUnit.setDamage(caster.getDamage(), caster.getOwner())
	newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HAUNT'), True)
	newUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_SUBDUE_ANIMAL'), False)
	newUnit.setLevel(caster.getLevel())
	newUnit.setExperienceTimes100(caster.getExperienceTimes100(), -1)# Changes Ghostwalker to a Haunt.

Am I correct in thinking that this code cycles through the entire promotioninfos file, checking if the caster has each promotion listed there? Or am I reading it wrong? That seems like a very inefficient way to do things.


Aside from that, another thought. Would the unit's name be lost when it transforms? Is there any way to make it be kept ?

more questions in future as I run into issues.
 
I don't see anywhere that the original unit is removed, though. But I don't recall the haunt spell leaving anything behind.
You have to look at the xml to understand spells. For the haunt transformation , the spell kills the caster.

I can't help but think that it would be better to look at Lichdom or Doviello upgrades. There is a tag that transforms the caster to the new unit, with no python necessary. There is also a method exposed in python that does the same.

Am I correct in thinking that this code cycles through the entire promotioninfos file, checking if the caster has each promotion listed there? Or am I reading it wrong? That seems like a very inefficient way to do things.

Yes, no, yes.

It is to my knowledge the only way to find out what promotions a unit has though. A big part of optimising code is realising that as long as it's not done often, it's not worth changing.

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." - Donald Knuth

Aside from that, another thought. Would the unit's name be lost when it transforms? Is there any way to make it be kept ?

I know it's possible to change a units name with python, and there probably is one to read it as well.
 
I can't help but think that it would be better to look at Lichdom or Doviello upgrades. There is a tag that transforms the caster to the new unit, with no python necessary. There is also a method exposed in python that does the same.

This is good. Can you give me some syntax, or point to an example, for the python version ? I'm definitely not going to be able to do this without python. Both of the above examples use only xml, it seems.
 
Anyone could explain thoroughly why some tags need a readpassX (2 or 3) and how does it work?
 
This is good. Can you give me some syntax, or point to an example, for the python version ? I'm definitely not going to be able to do this without python. Both of the above examples use only xml, it seems.

There is an example in CvEventManager, onUnitCreated. Scorpion clan goblins are first created as UNIT_SCORPION_CLAN_WHELP, and then converted to archers or chariots or riders.

It's also used in CvSpellInterface.postCombatWolfRider, babySpiderGrowth and spellArenaBattle for instance.
 
Ok, another little question.

The unit I'm transforming into, will have a Free promotion, that I want it to only have while in that form. It will have a different unitcombat(beast) to the caster(disciple).

If I mark that promotion as only valid for beast units, and set bValidate, will it be removed when the caster returns to his original form (and thus changes unitcombat to disciple)
 
Anyone could explain thoroughly why some tags need a readpassX (2 or 3) and how does it work?

Readpass2 runs immediately after the last item in the XML has loaded and is used for references to the same XML file (So if Combat 2 requires Combat 1, it needs to have Combat 1 exist before it can say that properly (know the enum for Combat 1), but Combat 1 lists Combat 2 as the PromotionNextLevel, so it needs Combat 2 loaded before it loads to do that properly... Only way to have both loaded before each other is to wait till the whole file is loaded.

Readpass3 runs when it is asked to run, and it loads items which had not actually existed previous to the XML being loaded (again, to get the proper enum and store just an Integer, like 35, instead of a full string, like PROMOTION_I_HAVE_USELESSLY_LONG_PROMOTION_NAMES, which saves memory). This is done by storing the string temporarily, taking up a LOT of extra memory during loading, but then when readpass3 runs it removes the string after getting the right enum to return to minimal memory use. This is required when files refer to each other. Every UnitType belongs to a UnitClass, so you need the classes loaded before the units to get the right enums, but each UnitClass lists a default UnitType, so you need the units loaded before the classes for THOSE enums...

Firaxis set up the order of files loading such that nothing which uses an array needs a readpass3 for it, so they don't give any nice examples of such. Near as I can tell, Kael used to shuffle things around to avoid the same, or completely avoid the readpass3 requirement. But eventually you WILL wind up with a recursive relationship (even if File A doesn't refer to File B which refers to it, you could wind up with an A->B->C->A relationship as well).

At this point though, there should be examples of how to load everything you can possibly need with readpass2 or 3 in my codebase. I've had to jump a few hurdles in figuring those things out, I like to imagine I am done with them ;)

Oh, and readpass2 is set up (if you build a new one) in the same command line of CvXMLLoadUtilitySet.cpp as calls the normal readpass, but you have to change the arguements to make pass2 happen. ReadPass3 you have to specifically request it to run when you are ready for it.

Self-embarassment admition: First time I had to deal with readpass3 was when merging in some code which created a new readpass3 in the same file Kael had already added one. Since they share a variable and I wasn't sure what to do, I cludged them together in a horrible way and it failed, so then I wrote a ::readPass4 and hoped that it would run itself for me :p
 
Another question. What, if anything, happens between promotion expiration checks, and the running of pyperturn functions?

If for example, I want a pyPerTurn which checks whether a unit still has a promotion which can expire, would there be anything visible to the end user between those two events? (it expiring, and the python checking that)
 
I can't answer your question, but it sounds like you're trying to duplicate the PythonOnRemove tag that already exists.
 
And another, actually. Is there any way to save what unit something used to be, when it transforms? Other than creating a unique set of promotions/spells/etc for every possible unit that might use it?

My Druid module I'm working on. Was thinking it might be nice to bind it to a promotion, rather than the druid unit. To allow for the possibility of mimics stealing it, and other assorted amusing combinations. but it's not going to work well if he always turns back into a druid rather than what he should be.
 
I can't answer your question, but it sounds like you're trying to duplicate the PythonOnRemove tag that already exists.

I'm so used to working with a language which is very lacking in functionality, so I tend to look for workarounds naturally. I'm rather enjoying the massive functionality that's provided here :)
 
I don't suppose there's any way to make a civic get better/do other things over time, as you get more techs open?
 
I'm stuck working on unt graphics because I cannot find how to keep a nif file the same when importing (either in blender or 3dsmax) and exporting without modifying anything, I always loose information about ATTACHABLES.

Do the art guys have a suggestion as to how to do so (Warkirby? help ...) :) ?
 
Back
Top Bottom