Another one of my Python attempts

Voyhkah

Undead
Joined
Apr 25, 2009
Messages
1,444
Location
Earth
Well, one of my units in my mod is supposed to destroy tanks by firing small nukes at them. So, I decided, why not make them make fallout when they attack? So I tried (again) at Python. here's what I made, copying and modifing existing code. Please don't laugh out loud when you read this, I've barely ever coded before. Ok, here it is:

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())
####Zapotec###
		iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
                if (unitX or unitY) == iZapotec
                    iX = pUnit.getX()
		    iY = pUnit.getY()
                    terrain.setHasFeature(gc.getInfoTypeForString("FEATURE_FALLOUT"), True)  
###Zapotec 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()))

So, how many mistakes, errors, or forgetifications did I make?

Please tell me so that I can improve!
 
It's all right, but I see a few things that need to be corrected.

terrain.setHasFeature(gc.getInfoTypeForString("FEATURE_FALLOUT"), should be
terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0). Additionally, you need to get terrain somehow before you call terrain.setFeatureType. You also need colons after your if statements in Python. (I forget them all the time and then wonder why my code doesn't work!) Also, your (unitX or unitY) == iZapotec should be (unitX == iZapotec) or (unitY == iZapotec). And you need to get pUnit from somewhere, I think. I'm pretty sure that should work otherwise.

I think it should work out to be something like this:

Code:
####Zapotec###

	iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
        
	if (unitX == iZapotec or unitY == iZapotec:)
		iX = pLoser.getX()
		iY = pLoser.getY()
		terrain = CyMap().plot(iX, iY)
		terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0)
		
###Zapotec END###
 
Right off I see (at least) 3 problems. This makes pretty much the whole thing wrong, I'm afraid, since every single line after the first (excluding the comments marking the beginning and end of your changes) has at least one problem...

First:
Code:
if (unitX or unitY) == iZapotec
will not do what you want. First, unitX and unitY are not the integer IDs of the unit types like iZapotec is, they are objects defined in PyHelpers.py of the class PyInfo. Also, the comparison is incorrect. And finally you are missing the ":" on the end.

Try:
Code:
if (pWinner.getUnitType() ==  iZapotec) or (pLoser.getUnitType() == iZapotec):

Second:
What is "pUnit"? You never define it. You have a pWinner and a pLoser, and a unitX and unitY. You do not have a pUnit.

This actually brings up a question about the logic of what you are doing. Shouldn't the fallout be at the location of the unit your special unit was fighting - that is, the one that is not a UNIT_ZAPOTEC? If so, you need to determine which unit, pWinner or pLoser, is that unit and then use that instead of the non-existant "pUnit".

Third:
What is "terrain"? You have never defined it. Before using it, like immediately preceding the line that uses it, you need to have something like:
Code:
terrain = CyMap().plot(iX, iY)

Second part of third problem:
There is no "setHasFeature", it is "setFeatureType" and the second arguent of that is not a true/false value but an integer (which should be 0 in this case). So what you want for that line is probably something more like this:
Code:
terrain.setFeatureType(gc.getInfoTypeForString("FEATURE_FALLOUT"), 0)

Good news, such as it is: that first line looks OK, and you can't really mess up a comment as long as you don't put any junk before the initial "#" character (so those lines are OK too).
 
Whoops, I made the same mistake with UnitInfo

Code:
####Zapotec###

	iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
        
	if (pWinner.getUnitType() ==  iZapotec) or (pLoser.getUnitType() == iZapotec):
		iX = pLoser.getX()
		iY = pLoser.getY()
		terrain = CyMap().plot(iX, iY)
		terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0)
		
###Zapotec END###
 
It works! Thanks! :thanx:
 
Now I've added a Unique Unit to a civ that replaces the Zapotec. And, I want the fallout to be created only when the Zapotec is fighting an armored Unit, because otherwise it wouldn't use it's nuclear missiles. Is this code right, or even close?

Code:
####Zapotec###

                iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
                iLiberator = gc.getInfoTypeForString("UNIT_NMC_LIBERATOR")
                iTank = gc.getInfoTypeForString ("UNITCOMBAT_ARMOR")
                if (pWinner.getUnitType() ==  iZapotec or iLiberator() or (pLoser.getUnitType() == iZapotec or iLiberator):
                    and (pWinner.getUnitType() == iTank() or (pLoser.getUnitType() == iTank):
                    iX = pLoser.getX()
                    iY = pLoser.getY()
                    terrain = CyMap().plot(iX, iY)
                    terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0)
		
###Zapotec END###
 
Code:
####Zapotec###

                iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
                iLiberator = gc.getInfoTypeForString("UNIT_NMC_LIBERATOR")
                iTank = gc.getInfoTypeForString ("UNITCOMBAT_ARMOR")
                if (pWinner.getUnitType() ==  iZapotec or iLiberator() or (pLoser.getUnitType() == iZapotec or iLiberator):
                    and (pWinner.getUnitType() == iTank() or (pLoser.getUnitType() == iTank):
                    iX = pLoser.getX()
                    iY = pLoser.getY()
                    terrain = CyMap().plot(iX, iY)
                    terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0)
		
###Zapotec END###

First, use tabs instead of spaces. It might give you crashes or weird functioning.
The first few lines seems pretty good, but I don't see why you're defining the "iLiberator". Mayby you should tell more about what you want to do? Also you seems to have little too much ()s in your if check. And I'd suggest to break your long if into two different checks. And last, use getUnitCombatType when you want to get the unit's combet type.
It should look something like this
Code:
####Zapotec###

		iZapotec = gc.getInfoTypeForString("UNIT_ZAPOTEC")
		iTank = gc.getInfoTypeForString ("UNITCOMBAT_ARMOR")
		if (pWinner.getUnitType() == iZapotec or pLoser.getUnitType() == iZapotec):
			if (pWinner.getUnitCombatType() == iTank or pLoser.getUnitCombatType() == iTank):
				iX = pLoser.getX()
				iY = pLoser.getY()
				terrain = CyMap().plot(iX, iY)
				terrain.setFeatureType(gc.getInfoTypeForString('FEATURE_FALLOUT'), 0)
		
###Zapotec END###
That should place fallout to the loser's plot.
 
The Liberator replaces the Zapotec for a civ and so also has to have the fallout effect.
 
Nevermind, lol. I thought I found a problem, but I misread NotSoGood's Python. You could also write that if statement like this, if it makes more sense to you.

if ( (pWinner.getUnitCombatType() == iZapotec and pLoser.getUnitCombatType() == iTank) or (pLoser.getUnitCombatType() == iZapotec and pLoser.getUnitCombatType() == iTank) )

I was gonna just delete this, but then I thought someone else might make the same misreading mistake that I did, so I rewrote the if to make more sense to people like me.
 
To be clear, Voyhkah, you can't OR or AND variables together the way you thought you could. No one else explained this, so I figured I'd help you out.

There are (at least in other languages, I don't know about Python) actual OR and AND operations that can be performed on variables. They are base-two operations, so the result is not going to be another iAnything recognizable to Civ. That's not what you want to have happen. Instead, you need to OR the entire conditions together: (a == b) or (a == c).
 
Hmmm...

What did you say? What does that mean?
 
There are 2 different Or operations. One is a logical comparison (also known as a boolean operator) that takes 2 values, does the comparison, and results in one true or false value. The other is a bitwise merging of the binary representation of the two integer values which results in another integer value. In Python, the "or" operator is always strictly a logical comparison, the bitwise "or" function is done via "A | B".

If you do "if A == B or C" then which of the two operations happens first? The answer is that in Python the "==" happens first (since comparisons are higher precedence than boolean operators), then the "or" happens. This results in it being the same as "if (A == B) or C". So it compares A and B and gets a value of either true or false. It then compares this true or false value with C, which is a number so you are trying to evaluate something like "if (false or 7)". In Python you can use a number in this way: if it is 0 it is false, if it is any other number it is true. This is clearly not what you want to be doing.

If you use "if A == (B or C)" what you get is also wrong. You should be able to figure out why.

What you need to use is "if (A == B) or (A == C)". Technically, you can leave off the parenthesis since the precedence of the "==" operator makes both of them happen first. I like to use the parenthesis anyway. It makes what you meant to do much clearer. It also helps avoid confusion for people who program in multiple languages, since they don't all use the same operator precedences. Relying on parenthesis to make it do what you want always works, but relying on operator precedence only works if the precedences are what you think they are at the time.
 
Ahhhh... I get it.

so

if (iUnitthing == isomething) or (iUnitThing == iSomething)
 
Back
Top Bottom