Govannon Spell adjustment

Pickly

Prince
Joined
Jun 5, 2009
Messages
535
Over the past several days (on and off, in between other things) I've been trying to adjust govannon's Teach Spellcasting spell so that it effects all of a civilizations units rather than merely the units in the square, but have so far had trouble getting the effect to work.

To see if my understanding of the spell is correct (I have done some programming in the past, though not with Python, and have only just started adjusting some civ 4 stuff, so while I think i can sort of tell what the different parts of the code are doing, I may well be missing some parts.):

"req(spell)" is just for AI use, to determine whether it should cast the spell or not? (I notice a command along the lines of "if player is not human" for some other requirements, and other spells don't have this python command at all, despite only being castable in certain situations, but I am checking this just in case.)

Spoiler :
Code:
def spellTeachSpellcasting(caster):
	iAnimal = gc.getInfoTypeForString('UNITCOMBAT_ANIMAL')
	iBird = gc.getInfoTypeForString('SPECIALUNIT_BIRD')
	iChanneling1 = gc.getInfoTypeForString('PROMOTION_CHANNELING1')
	lList = []
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_AIR1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_AIR1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_BODY1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_BODY1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHAOS1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_CHAOS1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DEATH1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_DEATH1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_EARTH1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_EARTH1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ENCHANTMENT1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_ENCHANTMENT1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ENTROPY1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_ENTROPY1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_FIRE1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_FIRE1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ICE1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_ICE1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_LAW1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_LAW1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_LIFE1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_LIFE1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_METAMAGIC1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_METAMAGIC1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_MIND1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_MIND1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_NATURE1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_NATURE1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SHADOW1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_SHADOW1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SPIRIT1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_SPIRIT1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SUN1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_SUN1')]
	if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_WATER1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_WATER1')]
	pPlot = caster.plot()
	iPlayer = caster.getOwner()
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getOwner() == iPlayer:
			if pUnit.isAlive():
				if pUnit.getUnitCombatType() != iAnimal:
					if pUnit.getSpecialUnitType() != iBird:
						for iProm in range(len(lList)):
							if not pUnit.isHasPromotion(lList[iProm]):
								pUnit.setHasPromotion(lList[iProm], True)
								if not pUnit.isHasPromotion(iChanneling1):
									pUnit.setHasPromotion(iChanneling1, True)

The first several lines appear to simply be to collect all the level 1 spellcasting promotions that the caster has in a list. For what I'm trying to do, it looks like I would not fool around with these. (hopefully)

The last 7 lines appear to be the part that actually gives other units the promotions, except for birds, animals, and nonalive units, and again is something I wouldn't change.

The lines from pPlot to if pUnit.getowner () are the ones that it seems I'll have to adjust, as these effect the range of the spell. I've tried adding this(among other things, though this seems the most sensible at the moment):

Code:
py = PyPlayer(caster.getOwner())
	for pUnit in py.getUnitList():

from spells such as Veil of Night and Warcry and removing the pPlot bits of code, which seems to fit what those spells do, but it just makes Teach Spellcasting unscastable in any situation.

This seems somewhat sensible, but being new at this I may well have missed some extra bit of code, so am curious if I'm at least going in the right direction, and perhaps what sorts of other stuff I might try, or some p-laces to look for information, to get the spell working the way I'm looking for.
 
Using this code, the spell canot be casted at all. (I've left out the first few lines and most of the promotion list stuff to save some space.)

Code:
if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_WATER1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_WATER1')]
	py = PyPlayer(caster.getOwner())
	for pUnit in py.getUnitList():
		if pUnit.getOwner() == iPlayer:
			if pUnit.isAlive():
				if pUnit.getUnitCombatType() != iAnimal:
					if pUnit.getSpecialUnitType() != iBird:
						for iProm in range(len(lList)):
							if not pUnit.isHasPromotion(lList[iProm]):
								pUnit.setHasPromotion(lList[iProm], True)
								if not pUnit.isHasPromotion(iChanneling1):
									pUnit.setHasPromotion(iChanneling1, True)
 
You probably need to also change the reqTeachSpellcasting function. Taking a quick glance, it's looking for available targets on the tile. You can either just remove the second part of the prereqs, or change it to do an all-unit check like you're doing for the spell itself.
 
So the requirement part of the python isn't just an A.I thing, like was mentioned at the beginning post? (seems strange, given what spells have this and which do not.)


Changing the requirement code to this:

Code:
if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_WATER1')):
		lList = lList + [gc.getInfoTypeForString('PROMOTION_WATER1')]
	if len(lList) > 0:
		py = PyPlayer(caster.getOwner())
		for pUnit in py.getUnitList():
			if pUnit.getOwner() == iPlayer:
				if pUnit.isAlive():
					if pUnit.getUnitCombatType() != iAnimal:
						if pUnit.getSpecialUnitType() != iBird:
							for iProm in range(len(lList)):
								if not pUnit.isHasPromotion(lList[iProm]):):
									return True
	return False

and the spell is still not castable.

For clarification, which part are you talking about as "the second part"? (so I could try that as well.)
 
The pyreq is used to codify any conditions that cannot be expressed by xml. It is also used to disallow the AI from casting spells when it would be a bad idea to cast them, as a sort of quarterway decent spell AI.

In your case, I'd just remove the pyreq altogether from the spell xml. Otherwise you have to loop over all your units to see if even one can be taught.

edit: I see you've already done that. However, your posted code contains a syntax error on the last but one line. Remove the smiley and it should work.
 
It's working now.

I deleted the requirement entirely (so not sure whether changing the typo in it would have effected things), and also deleted

Code:
if pUnit.getOwner() == iPlayer:

after noticing that there was no equivalent ot this in other such spells.

Thanks for the help to the people in this thread. (as this was the main reason I've starting fooling around modding FfH.)
 
Top Bottom