Mod-Modders Guide to Fall Further

Another thing to try: If your are using Visual Studio and you add a new variable to CvInfos you have to rebuild the whole project, not only your changed files. I ran into quite some trouble because of this behaviour in my early modding days. Got errors at the strangest of places.
I was about to write down the code more specifically to assure that i didn't place the code in wrong section, but then I figured I'll give the rebuild a try and
it fix the problem - I can now write the functional part of the code.

I would advise that you make the XML field be called fExtraXPValueAttack/Defense though, so that people know it will accept float values without having to read the schema.
I thought that I'll change that after i get the dll to load the new tags (and the code is mere copy of your decimal XP ;)).

Thanks for the help!
(and excuse me for my bad English)
 
Don't suppose anyone can answer my questions about the venomous web a few posts back?

I also have a few more questions, this time about collateral damage:

I'm looking to make a promotion, that will give collateral damage capability to any unit that has it.

I found these tags on the Catapult, but I'm not sure how well they'd apply to a promotion. Also, I'm not certain what the iCollateralDamage tag does, exactly. Does this mean catapults do 100% damage? it doesn't seem that way ingame.
<iCollateralDamage>100</iCollateralDamage>
<iCollateralDamageLimit>50</iCollateralDamageLimit>
<iCollateralDamageMaxUnits>6</iCollateralDamageMaxUnits>


And also, what is the iPower system all about? That tag is all over a lot of units and promotions.
 
Don't suppose anyone can answer my questions about the venomous web a few posts back?

I also have a few more questions, this time about collateral damage:

I'm looking to make a promotion, that will give collateral damage capability to any unit that has it.

I found these tags on the Catapult, but I'm not sure how well they'd apply to a promotion. Also, I'm not certain what the iCollateralDamage tag does, exactly. Does this mean catapults do 100% damage? it doesn't seem that way ingame.



And also, what is the iPower system all about? That tag is all over a lot of units and promotions.

The venemous web spell is likely used twice either so there can be two versions with different strengths, or because you can only specify one prereq unit, and they didn't want to tie it to a promotion.

Going to try and answer about the tags, not sure that I'm 100% correct here...

<iCollateralDamage> - Amount of unit's strength to apply towards collateral damage.

<iCollateralDamageLimit> - Amount of damage a unit is allowed to deal to enemies through collateral damage.

<iCollateralDamageMaxUnits> - Obviously, max amount of units it can damage.


So the damage limit specifies the total amount of damage the unit can do through collateral, while the CollateralDamage tag determines just how fast it can hit that limit.
 
<iCollateralDamage> - Amount of unit's strength to apply towards collateral damage.

Do you have any more indepth info on how this is calculated? Collateral damage always seemed random to me.

If I gave collateral 100 to Meshabber of Dis, for instance, and no damage limit. Would he just wipe out whole stacks with each attack?
 
From what I can tell, if you give him a collateral of 100 it will apply his full strength to the collateral dmg. You would still have to set the damage limit to 100, and include some arbitrarily high number for maxunits, although I think I remember reading something about a hard cap on the number of affected units?
 
Some questions about the Venomous Web spell

I'd like to give it to Mother. Or rather, a stronger version.

I noticed first of all, that there are two copies of it in the spellinfos. One for haruspex, and one for textus spiders

Why is this? Can't one spell be used for both?

Also, what is the <iResistModify>30</iResistModify> tag for? In my experience of using it, it seemed to be resisted a lot more than 30% of the time.

In which direction should I adjust this value if I wanted to make it work more often?

One spell can, but I'd have needed to add a promotion to be used as a prereq instead. If it were available to more units, that would be the better option. The other option is a PythonReq, but those are slower than either other option. The benefit of doing it as two spells over a promotion is that you can easily tweak the power for each specific unit. It also doesn't add more promotions to the 'pedia.

ResistModify increases the chances of the spell being resisted, making it easier to avoid the effect. As the spell is a stack-effect spell, it is desirable (from a modding point of view) that not all units are pinned in place by a single cast. A few casters working together are able to pin them down, but a single immobilize-all would be more potent than intended.

Codewise...

Code:
    int iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_BASE");
	iResist += getLevel() * 5;
    iResist += getResist();
    iResist += pCaster->getResistModify();
    iResist += GC.getSpellInfo((SpellTypes)iSpell).getResistModify();
    iResist += GET_PLAYER(getOwnerINLINE()).getResistModify();
    iResist += GET_PLAYER(pCaster->getOwnerINLINE()).getResistEnemyModify();
    if (plot()->isCity())
    {
        iResist += 10;
        iResist += plot()->getPlotCity()->getResistMagic();
    }
	if (iResist >= GC.getDefineINT("SPELL_RESIST_CHANCE_MAX"))
	{
		iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_MAX");
	}
	if (iResist <= GC.getDefineINT("SPELL_RESIST_CHANCE_MIN"))
	{
		iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_MIN");
	}
	return iResist;

There are BASE, MIN and MAX chances to resist set in the GlobalDefines. The chances can be modified by UnitLevel, Unit's natural resistance (including promotions), caster's "modifyResist" (Chanelling 2 and 3 etc decreases their chance to resist), the spell itself has a chance (which is the +30 in the case of web - easier to resist than the base) and then by any Player-specific resist/modify bonuses.

Combat promotions likewise increase the damage inflicted.

Basically you end up with a spell that damages units depending on the combat-promotion of the caster, which is useful for tying up portions of large stacks of low level units.

For reference - the BASE chance is 20% (so web is 50%), MIN is 5% and MAX is 100%.
 
would be nice, if the TempFeatureTimer stuff would be added to Cyplot. :) Right now there is only TempTerrainTimer in Cyplot
 
thanks for the info about venomous web, vehem.
Is it possible to make the damage effect always happen, regardless of whether the immobility is resisted or not?
without touching python....


And another question on a different topic.
The Shadowwalk promotion (shadow II) says in the tooltip Ignores Terrain Defense.
This is good, and it's what I want to do, but when copying the info from that promotion, it says something quite different....

<bIgnoreBuildingDefense>1</bIgnoreBuildingDefense>

Ignoring building defence, and terrain defence, are two very different things.
So what does this promotion actually do? And how can I make a promotion enable a unit to ignore terrain defence when attacking?
 
Will this code work? Bout to be leaving the house for a few hours, don't have time to test it myself. :p Only thing new in the function is in bold, just want to make sure I'm using the function correctly.

Edit: Never mind, managed to test it real quick. Works perfectly. :goodjob:

Code:
if gc.getPlayer(iPlayer).getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_DOVIELLO'):
	iDenPop=(pCity.getPopulation() - 1) * 0.4
	lList = ['UNIT_WOLF']
[B]	iBearDen = gc.getInfoTypeForString('BUILDINGCLASS_BEAR_DEN')
	iLionDen = gc.getInfoTypeForString('BUILDINGCLASS_LION_DEN')
	iMammothDen = gc.getInfoTypeForString('BUILDINGCLASS_MAMMOTH_DEN')
	iGriffinWeyr = gc.getInfoTypeForString('BUILDINGCLASS_GRIFFIN_WEYR')
	iStagCopse = gc.getInfoTypeForString('BUILDINGCLASS_STAG_COPSE')
			
	if pPlayer.getBuildingClassCount(iBearDen) >= 1:
		lList += ['UNIT_BEAR']	
	if pPlayer.getBuildingClassCount(iLionDen) >= 1:
		lList += ['UNIT_LION']		
	if pPlayer.getBuildingClassCount(iMammothDen) >= 1:
		lList += ['UNIT_MAMMOTH']
	if pPlayer.getBuildingClassCount(iGriffinWeyr) >= 1:
		lList += ['UNIT_GRIFFON']
	if pPlayer.getBuildingClassCount(iStagCopse) >= 1:
		lList += ['UNIT_STAG']				[/B]
	
	sAnimal = lList[CyGame().getSorenRandNum(len(lList), "Pick Animal")-1]
	iUnit = gc.getInfoTypeForString(sAnimal)
	iAnimalSpawnChance = 4 - iDenPop
			
	if CyGame().getGameSpeedType() == gc.getInfoTypeForString('GAMESPEED_QUICK'):
		iAnimalSpawnChance *= 1.5
	if CyGame().getGameSpeedType() == gc.getInfoTypeForString('GAMESPEED_EPIC'):
		iAnimalSpawnChance /= 1.5
	if CyGame().getGameSpeedType() == gc.getInfoTypeForString('GAMESPEED_MARATHON'):
		iAnimalSpawnChance /= 3
				
	if CyGame().getSorenRandNum(100, "Animal Spawn") < iAnimalSpawnChance:
		newUnit = pPlayer.initUnit(iUnit, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
		CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_ANIMAL_SPAWN",()),'AS2D_DISCOVERBONUS',1,gc.getUnitInfo(newUnit.getUnitType()).getButton(),ColorTypes(8),pCity.getX(),pCity.getY(),True,True)
 
You mean more units? Pretty sure it is possible. But they would be copies of what is already listed for the group in UnitInfos most likely. Not sure how easily you could add more, but you could just define extra units in Unitinfos if the promotion is meant for a specific selection of units.
 
I'm trying to import Tsentom1's Survival promotion and change it to a 100% chance. I've changed onCombatResult to the following and enabled USE_COMBAT_RESULT_CALLBACK in PythonCallbackDefines.
Spoiler :
Code:
	def onCombatResult(self, argsList):
		'Combat Result'
		pWinner,pLoser = argsList
		playerX = PyPlayer(pWinner.getOwner())
		unitX = PyInfo.UnitInfo(pWinner.getUnitType())
		playerY = PyPlayer(pLoser.getOwner())
		unitY = PyInfo.UnitInfo(pLoser.getUnitType())

## Survival Start ##

		pPlayer = gc.getPlayer(pLoser.getOwner())

		if pLoser.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SURVIVAL')):

			self.iResistance = self.getRandomNumber( 0 )

			if self.iResistance == 0:

				iUnit = pLoser.getUnitType()
				pClearPlot = self.findClearPlot(pLoser)
				pPlot = pLoser.plot()

				newUnit = pPlayer.initUnit(iUnit, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				pLoser.setDamage(90, False)
				newUnit.convert(pLoser)
				pLoser.setDamage(100, False)
				newUnit.finishMoves()

## Survival End ##

		if (not self.__LOG_COMBAT):
			return
		if playerX and playerX and unitX and playerY:
			CvUtil.pyPrint('Player %d Civilization %s Unit %s has defeated Player %d Civilization %s Unit %s' 
				%(playerX.getID(), playerX.getCivilizationName(), unitX.getDescription(), 
				playerY.getID(), playerY.getCivilizationName(), unitY.getDescription()))

How do I get it to work? And if it's impossible (or just easier) how can I include a new type immortality that reduces health to 10% on a lost battle and doesn't transport the unit back to the capital? Also, I'm trying to make it the ability of a promotion, not a specific type of unit.

EDIT: Also, how do make a promotion that is lost on defeat, instead of just combat? And if it requires python to remove it, does it still grant any promotion that the former degrades to? And if not, how do I get losing a battle with a specific promotion to grant another?

Second unrelated question: Is it possible to create a new "Offensive Strikes" mechanic similar to Defensive Strikes? And how would I do it?

Please note that I'm just starting to edit python and as such can follow any advice that relies on ability to make my own code.
 
IS there a way to block access to specific promotions, within a unit's xml? Ie, wihtout adding a new promotion specifically for it.

I'd like to give Meshabber Fire I to start with, and make him able to learn Fire II, but not Fire III. I have to give him channeling III for the Ashen Veil priest spells.
 
Just use PythonOnDeath instead of a full callback. Set PyOnDeath to call a python function which will set the unit to 10% health and then returns a false so that the death routine stops running.

To lose a promotion on Defeat, use PythonOnDefeat (or whatever we called it, maybe PythonOnCombatLost) to remove the promotion from the unit.

Any promotion which degrades will ALWAYS provide the degrade result when removed (except possibly when removing in worldbuilder, I know I had at least thought about blocking it then once). You can set up a python command to prevent degrade promotions from being applied though.


Anything is possible, it is just a question of how easy, and if you can figure out the hoops to jump through to make it work exactly how you want it to. Offensive Strikes would have quite a few hoops I imagine, and would certainly be better done in the DLL. IMO ranged attacks simulate the concept fairly well though.


Warkirby: Just use PromotionAllow and PromotionDeny
 
Just use PythonOnDeath instead of a full callback. Set PyOnDeath to call a python function which will set the unit to 10% health and then returns a false so that the death routine stops running.

To lose a promotion on Defeat, use PythonOnDefeat (or whatever we called it, maybe PythonOnCombatLost) to remove the promotion from the unit.

Thanks for the help, but as I said I'm not currently capable of making my own code, only copying and changing existing one (however that also how I started editing XML so I remain optimistic). Which existing code could I copy and change to get what I want?

Another small question: Which files do I have to edit in order to make a new UnitCombat?
 
Have you modded any spells? Look at how they are handled for an idea of how to fill in the fields. Can't remember if we actually use PyOnDeath through any promotions, I know that Alcinus uses it for his resurrection capability. Can look at how he works for some ideas there.

Setting a unit's health is done in the python for ressurection I think, so you can copy some from there. Removing a promotion is probably done quite often, but best I can think of is the Rust spell should certainly have some listed.

To make a new unitcombat you just add it to the list in UnitCombatInfos (in BasicInfos folder I think, there or Gameinfos)
 
I've searched a what feels like every Python file for: PyOnCombatDeath, Rust, Alcinus and ArcaneLacuna. Which file am I supposed to change?
 
Back
Top Bottom