A python question

RogerBacon

King
Joined
Nov 16, 2003
Messages
649
Hi,

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())
		# make sure the attacker won
                         if (pLoser.getOwner() != theGame.getActivePlayer()):
                             # do stuff

I thought the above if statement would only be executed if the active player's unit won. It turns out, however, that it only works if the human player's unit wins the combat. getActivePlayer() returns the human player only and never an AI.

Is there any easy way to find out if the winner of a fight was the attacker or defender?

Roger Bacon
 
Well, you could check movement remaining. An attacker always has movement reduced, whereas a defender doesn't have movement reduced.
 
Dale said:
Well, you could check movement remaining. An attacker always has movement reduced, whereas a defender doesn't have movement reduced.
Unless the defending unit has already moved and their moves are set to 0.
 
Moves are reset at the end of the turn. Otherwise, a defender would always fail a canDefend check.
 
Dale said:
Moves are reset at the end of the turn. Otherwise, a defender would always fail a canDefend check.
From what I can tell this is not true. After a 20 second search I couldn't find anything to do with movement in there. How would this work with simultanous moves anyway?

CyUnit.isDefending() or CyUnit.isAttacking() might work. I don't know if these still function after the the battle has a result or not.
 
As a note, never use .getActivePlayer() as it messes up multiplayer.
 
The Great Apple said:
From what I can tell this is not true. After a 20 second search I couldn't find anything to do with movement in there. How would this work with simultanous moves anyway?

CyUnit.isDefending() or CyUnit.isAttacking() might work. I don't know if these still function after the the battle has a result or not.

It's in there, just hard to notice because moves are set back to front as we would think. :) They're set as "the number of moves taken that turn".

Thus:
Code:
void CvUnit::changeMoves(int iChange)														
{
	setMoves(getMoves() + iChange);
}

This shows movement changing as "current moves" + "new moves". As the unit takes a step moves increases.

Therefore, we look for setMoves(0); which is the resetting value. There's two instances of it, one in CvCity::conscript(), and the other in CvUnit::doTurn(). The resetting of a units move is done at the end of the turn as evident from the code.

Code:
void CvUnit::doTurn()
{
	PROFILE("CvUnit::doTurn()")

............SNIP..................

	setMadeAttack(false);
	setMadeInterception(false);

	setReconPlot(NULL);

	setMoves(0);
}

You'll see it resets the attack flag, the interception flag, the recon flag and moves. :)

Dale
 
I was looking at the canDefend check - it doesn't seem to check to see that a unit has all it's moves.

I still can't see how this method would work with simultaneous moves.
 
The Great Apple said:
CyUnit.isDefending() or CyUnit.isAttacking() might work. I don't know if these still function after the the battle has a result or not.

I already tried CyUnit.isAttacking() but it is always false after a battle. I will try the moves thing tonight nad see if that works. I really can't believe they didn't give us a way to tell if the attacker or defender won the battle.

Roger Bacon
 
You could probably pass it additional args from the event trigger.

I was about to suggest CyUnit.isMadeAttack(), but this will fail in simultaneous moves as well.
 
This seems to be a tougher problem than I originally thought. I would guess using the combatLogCalc python function called before the battle commences and keep the variables of who is the attacker and who is the defender. When the battle ends, you can check who's who that way. Unfortunately, that's a pretty big hassle.

Of course, this short of modding the SDK to always pass the arguments as attacker first, then defender and deciding on your own who won and who lost by checking isDead. That's probably the easiest solution, although not entirely python.

I can't think of anything just in the units alone that will be able to check, since the functions that would typically be used for this (isAttacking and isDefending) have the variables they rely on reset before the combatResult function is called.
 
Gerikes said:
This seems to be a tougher problem than I originally thought. I would guess using the combatLogCalc python function called before the battle commences and keep the variables of who is the attacker and who is the defender. When the battle ends, you can check who's who that way. Unfortunately, that's a pretty big hassle.

Thanks Gerikes. That was the way to go and it was no hassle at all really.

set up a variable...
Code:
def __init__(self):

		# Store which unit is attacking
		self.AttackerOwner = -1

store it when combat begins...
Code:
def onCombatLogCalc(self, argsList):
		'Combat Result'	
		genericArgs = argsList[0][0]
		cdAttacker = genericArgs[0]
		cdDefender = genericArgs[1]
		iCombatOdds = genericArgs[2]
		self.AttackerOwner = cdAttacker.eOwner

Use it to determine if the attacker or defender won the combat...
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())
                if (self.AttackerOwner == pWinner.getOwner()):

Roger Bacon
 
Sorry to wander off topic here for a moment, but while we're on the topic of Python, assuming the following is all defined within a Class:
RogerBacon said:
Code:
def __init__(self):

		# Store which unit is attacking
		self.AttackerOwner = -1


def onCombatLogCalc(self, argsList):
		'Combat Result'	
		genericArgs = argsList[0][0]
		cdAttacker = genericArgs[0]
		cdDefender = genericArgs[1]
		iCombatOdds = genericArgs[2]
		self.AttackerOwner = cdAttacker.eOwner

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())
                if (self.AttackerOwner == pWinner.getOwner()):
... what is the scope of the variable self.AttackerOwner? When is the object instantiated -- in a given mod, is there only one instance of the EventManager object such that a variable set within it can always be called by another of its functions?

(Am I phrasing this all correctly? I'm not very good at OOP)
 
Padmewan said:
Sorry to wander off topic here for a moment, but while we're on the topic of Python, assuming the following is all defined within a Class:

... what is the scope of the variable self.AttackerOwner? When is the object instantiated -- in a given mod, is there only one instance of the EventManager object such that a variable set within it can always be called by another of its functions?

(Am I phrasing this all correctly? I'm not very good at OOP)

Yeah, I'm pretty sure there would only be one instance. Which means if you're in a game where a seperate attack can start while this one is still going (which I do believe is possible, see folks, this is what happens when you don't really PLAY Civ4, and you just mod this thing. Anyone's input on this would be great :p) this won't work. It will overwrite the variable.

I was thinking more keep the id of any attacking unit in a list of id's. Then you can quickly test whether the winning id or losing id in the attack list. I'm sure a unit can't be in simultaneous attacks, so as long as you are removing the id's from the list as you go, I'm sure you'd be fine.
 
All of the above is within a class. In this case it is class Promotions:

self.AttackerOwner exists for the class and for any instance of the class that is created (I believe).

In my CustomEventManager I have pro = Promotions.Promotions() and then I just call pro.onCombatResult(argsList) and pro.onCombatLogCalc(argsList).

I believe that if I wanted to use the variable anywhere outside of it's class I would use pro.AttackerOwner.

Roger Bacon
 
Top Bottom