Hopefully Quick Python Question

MaxAstro

Spiral Knight
Joined
Dec 18, 2007
Messages
645
This is basically the last barrier to me releasing my modmod, and I can't for the life of me figure it out.

I'm writing a spell for Amurite Wizards called Channel that allows them to act as living spellstaves. I got the basic mechanic working, and I've even managed to get it set up to target the strongest spellcaster on the tile.

The problem I am having is that I can't get the spell to consider the caster an invalid target. This means that if the caster is the strongest spellcaster on the tile, the spell we see that he has casted this turn (since he just cast Channel) and restore his ability to cast instantly. This makes it impossible to Channel for units weaker than the caster, which is less than ideal.

Can someone take a look at this code and tell me why it's still considering the caster a valid target?

EDIT: Here's the code.

Code:
def spellChannel(caster):
	pPlot = caster.plot()
	iBestValue = 0
	pTarget = -1
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		iTargetValue = 0
		if pUnit.isHasCasted() and pUnit != caster and pUnit.getOwner() == caster.getOwner():
			iTargetValue += pUnit.getLevel()
			if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING1')):
				iTargetValue += 10
			if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING2')):
				iTargetValue += 100
			if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING3')):
				iTargetValue += 1000
			if pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ADEPT'):
				iTargetValue += 5
			if iTargetValue > iBestValue:
				iBestValue = iTargetValue
				pTarget = pUnit
	if not pTarget == -1:
		pTarget.setHasCasted(False)
 
sorry for not being able to help you out :p

I just wanted to tell you that your modmod looks very promising and I'd love to see your changes in FF ;)
 
I think the problem is that pUnit is a helper class and whoever implemented it forgot to implement __eq__ .
But I can't find the source so I can't say for sure.


As a quick fix, you could try

Code:
def spellChannel(caster):
    caster.setHasCasted(False)
    pPlot = caster.plot()
    iBestValue = 0
    pTarget = -1
    for i in range(pPlot.getNumUnits()):
        pUnit = pPlot.getUnit(i)
        iTargetValue = 0
        if pUnit.isHasCasted() and pUnit.getOwner() == caster.getOwner():
            iTargetValue += pUnit.getLevel()
            if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING1')):
                iTargetValue += 10
            if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING2')):
                iTargetValue += 100
            if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING3')):
                iTargetValue += 1000
            if pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ADEPT'):
                iTargetValue += 5
            if iTargetValue > iBestValue:
                iBestValue = iTargetValue
                pTarget = pUnit
    if not pTarget == -1:
        pTarget.setHasCasted(False)
        caster.setHasCasted(True)
 
Ah, that's a clever idea and should work fine. Thank you much.
 
I think you're trying to do too much with one function. I'd split the unit-finding logic into it's own function and use it for a requirements function (reqChannel) and the main function (spellChannel). That way you can control who can use the spell based on that.

Also, this may be a matter of style, but I cringe whenever I see more than 2 or 3 long boolean statements on one line. In my view it's better to split them into separate if statements so it's easier to see the flow of control and find which statement is giving trouble.
Code:
def reqChannel(caster):
	pTarget = findChannelTarget(caster)
	if pTarget != -1 and pTarget != caster:
		return true
	else:
		return false

def spellChannel(caster):
	pTarget = findChannelTarget(caster)
	pTarget.setHasCasted(False)
		
def findChannelTarget(caster):
	pPlot = caster.plot()
	iBestValue = -1
	pTarget = -1
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		iTargetValue = 0
		if pUnit != caster:
			if pUnit.isHasCasted():
				if pUnit.getOwner() == caster.getOwner():
					iTargetValue += pUnit.getLevel()
					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING1')):
						iTargetValue += 10
					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING2')):
						iTargetValue += 100
					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_CHANNELING3')):
						iTargetValue += 1000
					if pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ADEPT'):
						iTargetValue += 5
					if iTargetValue > iBestValue:
						iBestValue = iTargetValue
						pTarget = pUnit
	return pTarget
 
Also, this may be a matter of style, but I cringe whenever I see more than 2 or 3 long boolean statements on one line.

I do too. I also cringe when someone uses "false" and "true" instead of "False" and "True", "if some_boolean == False:" instead of "if not some_boolean:" and when they chain several exclusive if-statements together without using elif.


Code:
def reqChannel(caster):
	pTarget = findChannelTarget(caster)
	if pTarget != -1 and pTarget != caster:
		return true
	else:
		return false

No need to check if the target is the caster , since the target can't be the caster.

But like I said, I don't think whatever class caster and pTarget are implements __eq__ and __ne__ , so it doesn't work anyway. I'm still trying to find them.
 
Top Bottom