Modders Guide to FfH2

Hey, everyone
I had an idea about a unit that could rebel, and then recruit units. After I started to work on it, I saw that the summon feature might use Python? I was copying the promotions and effects to raise a skeleton when I saw it, and was wondering if a change in python is needed, or not.
Basically, what I want is to have unit randomly rebel and become barbarian, then also spawn underlings until the unit is killed. After accumulating a nice sized army, the horde should attack (though the barbarians attack if they get a nice enough army anyways, right?). It seems like it should be an easy trick, though I just don't know how to do it yet.
Cheers
 
Which files and how i can use your improvements (bandit camps i really don't know their name and etc) which spawn barbarian units, i just want this. Which XML files, PY files and SDK files is need for that?
 
You would use the <SpawnUnitType> tag in C:\Program Files (x86)\Firaxis Games\Sid Meier's Civilization 4\Beyond the Sword\Mods\Fall from Heaven 2\Assets\XML\Terrain\CIV4ImprovementInfos.xml. You put the type of unit between those tabs at the end of the improvement's defines, like <SpawnUnitType>UNIT_GOBLIN_SCORPION_CLAN</SpawnUnitType>

Since this tag is not used in base BtS, using them in an unrelated mod would require editing Assets\XML\Terrain\CIV4TerrainSchema.xml and compile a new DLL making changes to CvGameTextMgr.cpp, CvInfos.cpp, CvInfos.h, CvPlot.cpp, CvUnit.cpp, and CyInfoInterface2.cpp.
 
I try to merge yesterday but i was confused, don't know which part of code to use, i am found SpawnUnitType tag in source codes. And do you know where i can found source files for RifE (Rise from Erebus) in rife spawn works more better than in FFH2 ?
 
I want to use all tags from PromotionInfos (FfH2), can someone tell me which .py, .cpp and .h files i must use? Merge BTS + PromotionInfos tags (FfH2).
 
I try to merge yesterday but i was confused, don't know which part of code to use, i am found SpawnUnitType tag in source codes. And do you know where i can found source files for RifE (Rise from Erebus) in rife spawn works more better than in FFH2 ?

I want to use all tags from PromotionInfos (FfH2), can someone tell me which .py, .cpp and .h files i must use? Merge BTS + PromotionInfos tags (FfH2).

Rife Source code is here - https://sourceforge.net/p/rife/code/HEAD/tree/

You can also find the source code for my mod on Sourceforge - https://sourceforge.net/projects/tholalsffhaimod/

I dont think you need any python files for the new Promotion tags. You'll have to search for each tag in the .ccp files and .h files to figure out what lines of code need to be merged.
 
Basically, what I want is to have unit randomly rebel and become barbarian, then also spawn underlings until the unit is killed. After accumulating a nice sized army, the horde should attack (though the barbarians attack if they get a nice enough army anyways, right?). It seems like it should be an easy trick, though I just don't know how to do it yet.
Cheers

You would probably want to put your code in CvEventManager - onBeginPlayerTurn

Loop through the units to randomly choose ones to give the barbarian promotion to, and then also check for units with that promotion. If they have it, then try and spawn some underlings.
 
@Tholal
Thanks, i must found tags name from XML in .cpp and .h and merge all with BTS (FfH2 or RifE i will choose better or easier). Did Promotion and Spells or Unit infos had some relationship? I only want to use promotion tags and later merge this tags with some another tags and some another SDK mod components.

And of course i will see you mods and interesting stuff.
 
Hi.
I am working on a szenario on Games of Throne based on Magistermodmod.
I would like to integrate the gameoption that the first civic wins that has built its palace in Kings Landing.

I am new with modding, so I need help. I know it has to be done in the ScenarioFunctions.py but I have no idea how to write it.

If anyone can help me, I would be so glad.
 
I recently tried giving a building a negative number for <iNumFreeBonuses>, and noticed something odd.


If I try to make a building provide -1 sources of Death Mana then it instead grants +3 sources, but when I try t make it grant -2 then it does indeed reduce the number of Death mana the player controls by 2.

Any idea why this might be happening?


(Note that this is of course in my modmod, which uses the MNAI DLL. I was thinking that I might prefer to have the Sidar's Shrine of Arawn UB reduce the amount of Death mana controlled by 1 per building, rather than making the mana completely unavailable or granting such a large unhappiness penalty for possessing the resource. Having he building provide 3 Death mana is very wrong, but ending up with -20 death mana like in my last game seems odd too.)
 
-1 is often used as a special designation. In this case, there's some weird code in getNumFreeBonuses. Not sure why it's doing this but there must be some reasoning behind it.

Code:
int CvGame::getNumFreeBonuses(BuildingTypes eBuilding)
{
	if (GC.getBuildingInfo(eBuilding).getNumFreeBonuses() == -1)
	{
		return GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getNumFreeBuildingBonuses();
	}
	else
	{
		return GC.getBuildingInfo(eBuilding).getNumFreeBonuses();
	}
}
 
Most of the time those unique names are given via the python because they were created via an event (the priest of winter's get their names like this under def onProjectBuilt in CvEventManager.py) however you can also give them from a list of names like UNIT_ADVENTURER is done in CIV4UnitInfos.xml (this will require editing CIV4GameText_FFH2.xml with the names you want in the list)
 
Technically you can add a custom name to a unit's CIVUnitInfos.xml defied directly, without necessarily adding a TXT_KEY_ for it, and within Assets\XML\Text the file where you place a new TXT_KEY_ does not matter much.


Most of the units in the game which get a custom name have their named generated (pseudo-)randomly in CustomFunctions.py under def MarnokNameGenerator(self, unit):
Spoiler :
Code:
	def MarnokNameGenerator(self, unit):
		pPlayer = gc.getPlayer(unit.getOwner())	
		pCiv = pPlayer.getCivilizationType() 
		pReligion = pPlayer.getStateReligion()
		pAlign = pPlayer.getAlignment() 

		lPre=["ta","go","da","bar","arc","ken","an","ad","mi","kon","kar","mar","wal","he", "ha", "re", "ar", "bal", "bel", "bo", "bri", "car","dag","dan","ma","ja","co","be","ga","qui","sa"]
		lMid=["ad","z","the","and","tha","ent","ion","tio","for","tis","oft","che","gan","an","en","wen","on","d","n","g","t","ow","dal"]
		lEnd=["ar","sta","na","is","el","es","ie","us","un","th", "er","on","an","re","in","ed","nd","at","en","le","man","ck","ton","nok","git","us","or","a","da","u","cha","ir"]
	
		lEpithet=["red","blue","black","grey","white","strong","brave","old","young","great","slayer","hunter","seeker"]
		lNoun=["spirit","soul","boon","born","staff","rod","shield","autumn","winter","spring","summer","wit","horn","tusk","glory","claw","tooth","head","heart", "blood","breath", "blade", "hand", "lover","bringer","maker","taker","river","stream","moon","star","face","foot","half","one","hundred","thousand"]
		lSchema=["CPME","CPMESCPME","CPESCPE","CPE","CPMME","CPMDCME","CPMAME","KCPMESCUM","CPMME[ the ]CX", "CPMESCXN", "CPMME[ of ]CPMME", "CNNSCXN"]

		if pAlign == gc.getInfoTypeForString('ALIGNMENT_EVIL'):
			lNoun = lNoun + ["fear","terror","reign","brood","snare","war","strife","pain","hate","evil","hell","misery","murder","anger","fury","rage","spawn","sly","blood","bone","scythe","slave","bound","ooze","scum"]
			lEpithet=["dark","black","white","cruel","foul"]		
	
		if pReligion == gc.getInfoTypeForString('RELIGION_THE_ASHEN_VEIL'):
			lEpithet = lEpithet + ["fallen","diseased","infernal","profane","corrupt"]
			lSchema = lSchema + ["CPME[ the ]CX"]
		if pReligion == gc.getInfoTypeForString('RELIGION_OCTOPUS_OVERLORDS'):
			lPre = lPre + ["cth","cht","shu","az","ts","dag","hy","gla","gh","rh","x","ll"]		
			lMid = lMid + ["ul","tha","on","ug","st","oi"]	
			lEnd = lEnd + ["hu","on", "ha","ua","oa","uth","oth","ath","thua", "thoa","ur","ll","og","hua"]
			lEpithet = lEpithet + ["nameless","webbed","deep","watery"]
			lNoun = lNoun + ["tentacle","wind","wave","sea","ocean","dark","crab","abyss","island"]
			lSchema = lSchema + ["CPMME","CPDMME","CPAMAME","CPMAME","CPAMAMEDCPAMAE"]
		if pReligion == gc.getInfoTypeForString('RELIGION_THE_ORDER'):
			lPre = lPre + ["ph","v","j"]		
			lMid = lMid + ["an","al","un"]	
			lEnd = lEnd + ["uel","in","il"]
			lEpithet = lEpithet + ["confessor","crusader", "faithful","obedient","good"]
			lNoun = lNoun + ["order", "faith", "heaven","law"]
			lSchema = lSchema + ["CPESCPME","CPMESCPE","CPMESCPME", "CPESCPE"]
		if pReligion == gc.getInfoTypeForString('RELIGION_FELLOWSHIP_OF_LEAVES'):
			lPre = lPre + ["ki","ky","yv"]		
			lMid = lMid + ["th","ri"]	
			lEnd = lEnd + ["ra","el","ain"]
			lEpithet = lEpithet + ["green"]
			lNoun = lNoun + ["tree","bush","wood","berry","elm","willow","oak","leaf","flower","blossom"]
			lSchema = lSchema + ["CPESCN","CPMESCNN","CPMESCXN"]		
		if pReligion == gc.getInfoTypeForString('RELIGION_RUNES_OF_KILMORPH'):
			lPre = lPre + ["bam","ar","khel","ki"]		
			lMid = lMid + ["th","b","en"]	
			lEnd = lEnd + ["ur","dain","ain","don"]
			lEpithet = lEpithet + ["deep","guard","miner"]
			lNoun = lNoun + ["rune","flint","slate","stone","rock","iron","copper","mithril","thane","umber"]
			lSchema = lSchema + ["CPME","CPMME"]	
		if pReligion == gc.getInfoTypeForString('RELIGION_THE_EMPYREAN'):
			lEpithet = lEpithet + ["radiant","holy"]
			lNoun = lNoun + ["honor"]
		if pReligion == gc.getInfoTypeForString('RELIGION_COUNCIL_OF_ESUS'):
			lEpithet = lEpithet + ["hidden","dark"]
			lNoun = lNoun + ["cloak","shadow","mask"]
			lSchema = lSchema + ["CPME","CPMME"]	

		if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ENRAGED')) == True:
			# I have left this as a copy of the Barbarian, see how it goes, this might do the trick. I plan to use it when there is a chance a unit will go Barbarian anyway.
			lPre = lPre + ["gru","bra","no","os","dir","ka","z"]
			lMid = lMid + ["g","ck","gg","sh","b","bh","aa"]
			lEnd = lEnd + ["al","e","ek","esh","ol","olg","alg"]
			lNoun = lNoun + ["death", "hate", "rage", "mad","insane","berserk"]		
			lEpithet = lEpithet + ["smasher", "breaker", "mangle","monger"]

		if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CRAZED')) == True:
			# might want to tone this down, because I plan to use it as possession/driven to madness, less than madcap zaniness.
			lPre = lPre + ["mad","pim","zi","zo","fli","mum","dum","odd","slur"]
			lMid = lMid + ["bl","pl","gg","ug","bl","b","zz","abb","odd"]
			lEnd = lEnd + ["ad","ap","izzle","onk","ing","er","po","eep","oggle","y"]	
		
		if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_VAMPIRE')) == True:
			lPre = lPre + ["dra","al","nos","vam","vla","tep","bat","bar","cor","lil","ray","zar","stra","le"]
			lMid = lMid + ["cul","u","car","fer","pir","or","na","ov","sta"]
			lEnd = lEnd + ["a","d","u","e","es","y","bas","vin","ith","ne","ak","ich","hd","t"]	

		if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON')) == True:
			lPre = lPre + ["aa","ab","adr","ah","al","de","ba","cro","da","be","eu","el","ha","ib","me","she","sth","z"]
			lMid = lMid + ["rax","lia","ri","al","as","b","bh","aa","al","ze","phi","sto","phe","cc","ee"]
			lEnd = lEnd + ["tor","tan","ept","lu","res","ah","mon","gon","bul","gul","lis","les","uz"]
			lSchema = ["CPMMME","CPMACME", "CPKMAUAPUE", "CPMMME[ the ]CNX"]				
		
		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_HILL_GIANT'):
			lPre = lPre + ["gor","gra","gar","gi","gol"]
			lMid = lMid + ["gan","li","ri","go"]
			lEnd = lEnd + ["tus","tan","ath","tha"]
			lSchema = lSchema +["CXNSCNN","CPESCNE", "CPMME[ the ]CX"]		
			lEpithet = lEpithet + ["large","huge","collossal","brutal","basher","smasher","crasher","crusher"]		
			lNoun = lNoun + ["fist","tor","hill","brute","stomp"]

		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_LIZARDMAN'):
			lPre = lPre + ["ss","s","th","sth","hss"]
			lEnd = lEnd + ["ess","iss","ath","tha"]
			lEpithet = lEpithet + ["cold"]			
			lNoun = lNoun + ["hiss","tongue","slither","scale","tail","ruin"]
			lSchema = lSchema + ["CPAECPAE","CPAKECPAU","CPAMMAE"]		
		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_FIRE_ELEMENTAL') or unit.getUnitType() == gc.getInfoTypeForString('UNIT_AZER'):
			lPre = lPre + ["ss","cra","th","sth","hss","roa"]
			lMid = lMid + ["ss","ck","rr","oa","iss","tt"]		
			lEnd = lEnd + ["le","iss","st","r","er"]
			lNoun = lNoun + ["hot", "burn","scald","roast","flame","scorch","char","sear","singe","fire","spit"]			
			lSchema = ["CNN","CNX","CPME","CPME[ the ]CNX","CPMME","CNNSCPME"]
		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_WATER_ELEMENTAL'):
			lPre = lPre + ["who","spl","dr","sl","spr","sw","b"]
			lMid = lMid + ["o","a","i","ub","ib"]		
			lEnd = lEnd + ["sh","p","ter","ble"]
			lNoun = lNoun + ["wave","lap","sea","lake","water","tide","surf","spray","wet","damp","soak","gurgle","bubble"]			
			lSchema = ["CNN","CNX","CPME","CPME[ the ]CNX","CPMME","CNNSCPME"]	
		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_AIR_ELEMENTAL'):
			lPre = lPre + ["ff","ph","th","ff","ph","th"]
			lMid = lMid + ["oo","aa","ee","ah","oh"]		
			lEnd = lEnd + ["ff","ph","th","ff","ph","th"]
			lNoun = lNoun + ["wind","air","zephyr","breeze","gust","blast","blow"]			
			lSchema = ["CNN","CNX","CPME","CPME[ the ]CNX","CPMME","CNNSCPME"]	
		if unit.getUnitType() == gc.getInfoTypeForString('UNIT_EARTH_ELEMENTAL'):
			lPre = lPre + ["gra","gro","kro","ff","ph","th"]
			lMid = lMid + ["o","a","u"]		
			lEnd = lEnd + ["ck","g","k"]
			lNoun = lNoun + ["rock","stone","boulder","slate","granite","rumble","quake"]			
			lSchema = ["CNN","CNX","CPME","CPME[ the ]CNX","CPMME","CNNSCPME"]	
	
		# SEA BASED
		# Check for ships - special schemas
		if unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_NAVAL'):
			lEnd = lEnd + ["ton","town","port"]
			lNoun = lNoun + ["lady","jolly","keel","bow","stern", "mast","sail","deck","hull","reef","wave"]
			lEpithet = lEpithet + ["sea", "red", "blue","grand","barnacle","gull"]
			lSchema = ["[The ]CNN", "[The ]CXN", "[The ]CNX","[The ]CNSCN", "[The ]CNSCX","CPME['s ]CN","[The ]CPME", "[The ]CNX","CNX","CN['s ]CN"]
	
		# # #
		# Pick a Schema
		sSchema = lSchema[CyGame().getSorenRandNum(len(lSchema), "Name Gen")-1]
		sFull = ""
		sKeep = ""
		iUpper = 0
		iKeep = 0
		iSkip = 0
	
		# Run through each character in schema to generate name
		for iCount in range (0,len(sSchema)):
			sAdd=""
			iDone = 0
			sAction = sSchema[iCount]
			if iSkip == 1:
				if sAction == "]":
					iSkip = 0
				else:
					sAdd = sAction
					iDone = 1		
			else:					# MAIN SECTION
				if sAction == "P": 	# Pre 	: beginnings of names
					sAdd = lPre[CyGame().getSorenRandNum(len(lPre), "Name Gen")-1]
					iDone = 1
				if sAction == "M":	# Mid 	: middle syllables
					sAdd = lMid[CyGame().getSorenRandNum(len(lMid), "Name Gen")-1]	
					iDone = 1	
				if sAction == "E":	# End	: end of names
					sAdd = lEnd[CyGame().getSorenRandNum(len(lEnd), "Name Gen")-1]
					iDone = 1
				if sAction == "X":	# Epithet	: epithet word part
					#epithets ("e" was taken!)
					sAdd = lEpithet[CyGame().getSorenRandNum(len(lEpithet), "Name Gen")-1]
					iDone = 1
				if sAction == "N":	# Noun	: noun word part
					#noun
					sAdd = lNoun[CyGame().getSorenRandNum(len(lNoun), "Name Gen")-1]	
					iDone = 1
				if sAction == "S":	# Space	: a space character. (Introduced before [ ] was possible )
					sAdd =  " "
					iDone = 1
				if sAction == "D":	# Dash	: a - character. Thought to be common and useful enough to warrant inclusion : Introduced before [-] was possible 
					sAdd =  "-"
					iDone = 1
				if sAction == "A":	# '		: a ' character - as for -, introduced early
					sAdd = "'" 
					iDone = 1
				if sAction == "C":	# Caps	: capitalizes first letter of next phrase generated. No effect on non-letters.
					iUpper = 1
				if sAction == "K":	# Keep	: stores the next phrase generated for re-use with U
					iKeep = 1
				if sAction == "U":	# Use	: re-uses a stored phrase.
					sAdd = sKeep
					iDone = 1
				if sAction == "[":	# Print	: anything between [] is added to the final phrase "as is". Useful for [ the ] and [ of ] among others.
					iSkip = 1
			# capitalizes phrase once.	
			if iUpper == 1 and iDone == 1:
				sAdd = sAdd.capitalize()
				iUpper = 0
			# stores the next phrase generated.	
			if iKeep == 1 and iDone == 1:
				sKeep = sAdd
				iKeep = 0
			# only adds the phrase if a new bit was actally created.
			if iDone == 1:
				sFull = sFull + sAdd

		# trim name length			
		if len(sFull) > 25:
			sFull = sFull[:25]		
		#CyInterface().addMessage(caster.getOwner(),True,25,"NAME : "+sFull,'AS2D_POSITIVE_DINK',1,'Art/Interface/Buttons/Spells/Rob Grave.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)

		return sFull
 
I have a question regarding the flying promotion. I could have sworn on my old computer, when I had a mod going that the flying promotion actually raised the unit up in the air a bit. I am not seeing that on my Orbis modmod. I don't know if I forgot what I did to get that effect or I am making that up. Does anyone know what I mean? If not, any thoughts on graphically showing the unit up "while flying"? I seem to recall the waterwalking did something similar, lowering the unit, but I could be mistaken.
 
It's not in vanilla FfH II, that's for sure. It's been a while since I've played Orbis, but I don't remember the Flying promotion havign a graphical effect associated with it.

Don't know how you'd get the effect you'd want either.

I have a question regarding the flying promotion. I could have sworn on my old computer, when I had a mod going that the flying promotion actually raised the unit up in the air a bit. I am not seeing that on my Orbis modmod. I don't know if I forgot what I did to get that effect or I am making that up. Does anyone know what I mean? If not, any thoughts on graphically showing the unit up "while flying"? I seem to recall the waterwalking did something similar, lowering the unit, but I could be mistaken.
 
Top Bottom