Python : help please !

Fabrysse

Charming-snake learner
Joined
Sep 11, 2006
Messages
430
Location
Toulouse - France
Hello,
I am a python beginner. And this snake is driving me crazy ! :crazyeye:
;)

  • I have created a class in wich I only work on "onBeginPlayerTurn".
  • With "SdToolKit" I can see that my class is run by main program (messages written on screan).
  • In "PythonErr2.log", there are no errors.

Now, I have a few questions :
  1. Wich file must I import to use CyCamera() ?
  2. How can I create a new unit while running the "onBeginPlayerTurn" function ?

Can you help me ?...
 
Thank's Teg_Navanis, but that doesn't work. :(

What is my project ?
At the beginning of each player turn, if this player has built a National Project that I have added in the XML files, he has a random chance that some specific troops (added in XML files too) appear in the
city where is the building. Then, if the player is human, camera focuses on the city, and a popup tells him that a new unit was created there.

Here is my code in a new file called "InternationalTroops.py" (comments explain what I want to) :

Code:
from CvPythonExtensions import *
import CvUtil
import PyHelpers
import Popup as PyPopup
import pickle
import random
import CvTranslator
# Import SdToolkit to print infos on screen (while testing).
import SdToolKit


# globals
gc = CyGlobalContext()
PyPlayer = PyHelpers.PyPlayer
PyCity = PyHelpers.PyCity
PyInfo = PyHelpers.PyInfo
		

#the main class
class InternationalTroops:
	"InterTroops random event class"
	# On begin turn of each player :
	def onBeginPlayerTurn(self, argsList):  

		iGameTurn, iPlayer = argsList
		py = PyPlayer(iPlayer)
		building = 0
		
		#Test : print on screen the Player ID
		apIDplayer = PyPlayer(iPlayer).getID()
		SdToolKit.sdEcho(apIDplayer)
		
		# the following randnum will determine if troops will be added
		randnum = random.randint(1, 5)
		if (randnum <= 1):
		
			"calculate the eligible cities to host the InterTroops (only 1 per Civ in fact : it's a national project)"
			apCityList = PyPlayer(iPlayer).getCityList()
			for pCity in apCityList:
				#a city is only eligible for InterTroops if it has a built INTERNATIONAL_CALLING improvement
				if (pCity.hasBuilding(gc.getInfoTypeForString("BUILDING_INTERNATIONAL_CALLING"))):  
					building =1
					pInTerTroopsCity = pCity
					#Test : print on sreen if building is built
					SdToolKit.sdEcho("Building : OK !")
					# Then create new unit
					pCity.getOwner().initUnit(gc.getInfoTypeForString("UNIT_INTERNATIONAL_TROOPS"), city.getX(), city.getY(), UnitAITypes.NO_UNITAI)

			if (isHuman(PyPlayer(iPlayer).getID()) and building ==1):        # Popup and Camera only for human players
		
				#Test : print on screen if player is human
				SdToolKit.sdEcho("Human player !")
				#Center the camera :
				camera = CyCamera()
				camera.JustLookAtPlot(self.pInTerTroopsCity.plot())
				#Open the Popup
				popup = PyPopup.PyPopup(-1)
				popup.addDDS('art\interface\screens\randomevents\intertroops.dds', 0, 0, 256, 256)
				popup.addSeparator()
				popup.setBodyString(CyTranslator().getText("TXT_KEY_INTERTROOPS_ARRIVAL", ()), "")
				popup.launch(true, PopupStates.POPUPSTATE_QUEUED)

What else ?
In "CvCustomEventManager.py" I added 3 lines.
2 lines at the top :
Code:
import InternationalTroops  # The file with my class
sho = InternationalTroops.InternationalTroops()
and 1 line in "def onBeginPlayerTurn"
Code:
sho.onBeginPlayerTurn(argsList)

What I have on screen ?
The main program enters in the class (I see my testing texts on screen). But the unit is not created, the camera not centered on city, the popup not opened...
And, when I play, my human player has the building requested built in a city, but on screen, the program doesn't show me the text "Building : OK!". It shows it for some other players...

No errors in "PythonErr2.log" file.


Where is/are my error(s) ?? Please help me !....
 
There are a few errors in your code that will need fixing before it will function.

Code:
apCityList = PyPlayer(iPlayer).getCityList()

You don't have to call PyPlayer(iPlayer) again. You can simply use py.getCityList() since you set py = PyPlayer(iPlayer) already.

Code:
pCity.getOwner().initUnit(gc.getInfoTypeForString("UNIT_INTERNATIONAL_TROOPS"), city.getX(), city.getY(), UnitAITypes.NO_UNITAI)

This is why there is no unit being initialized. It should be
Code:
[B]gc.getPlayer(pCity.getOwner())[/B].initUnit(gc.getInfoTypeForString("UNIT_INTERNATIONAL_TROOPS"), [B]pCity[/B].getX(), [B]pCity[/B].getY(), UnitAITypes.NO_UNITAI)

Unless isHuman() is a method you defined somewhere else in your file, then it doesn't do anything.
Code:
if (isHuman(PyPlayer(iPlayer)) and building ==1):
Try this, as long as PyPlayer(iPlayer).getCityList() gives you a list of city objects and not city integar id numbers, it should work fine.
Code:
if ([B]gc.getPlayer(pCity.getOwner()).isHuman()[/B]) and [B]([/B]building ==1)

Next check this line
Code:
camera.JustLookAtPlot(self.pInTerTroopsCity.plot())
First, there is no self.pInTerTroopsCity. In the above for loop you set pInTerTroopsCity not self.pInTerTroopsCity.
Second, the JustLookAtPlot() doesn't take a CyPlot it takes a CyPlot's NiPoint3. Change the for loop above to set self.pInTerTroopsCity and then try
Code:
camera.JustLookAtPlot(self.pInTerTroopsCity.plot().getPoint())

Give those a try and just keep in mind that each city, unit, plot, ect, has a Cy obj, usually denoted by pUnit, pCity or objUnit, objCity and each also has a int ID number represented with iPlayer, iUnit, iCity. Cy objects are used to get info on that obj and ID int are usually used to get the Cy obj.

If you have any more questions or still can't get it to work, repost your code and I'll see if i can help. :)
 
@Lord Olleus
Well... I suppose yes. The game writes messages sent (by my class) using SdToolKit elements, like the ID of current player (have a look just after the line "#Test : print on screen the Player ID").
That's why I think my class is run by the game, but some commands are wrong...
 
@Jeckel :king:
Thank you very much for your help !!!
I try that this evening.

To learn, I opened a lot of CIV Mods with python. But it isn't really easy to find the good way.
Your response will help me to progress, I'm sure.
Thanks again.
 
Here is the good code in InternationalTroops.py :

Code:
####################################################################
#    International Troops Event for "Second Revolution 2.0" MOD    #
####################################################################
#
# Author - Fabrysse (with Jeckel's help) 
#
# "Second Revolution" MOD was created by GarretSidzaka
#
# International Troops Event history :
# Version 1.0 (Oct. 2006)
# - initial release

from CvPythonExtensions import *
import CvUtil
import PyHelpers	
import Popup as PyPopup
import pickle		
import random
import CvTranslator

import SdToolKit




# globals
gc = CyGlobalContext()
PyPlayer = PyHelpers.PyPlayer
PyCity = PyHelpers.PyCity
PyInfo = PyHelpers.PyInfo
		


#the main class

class InternationalTroops:
	#"InterTroops random event class"
	# "On begin turn of each player :"
	def onBeginPlayerTurn(self, argsList):  

		iGameTurn, iPlayer = argsList
		py = PyPlayer(iPlayer)
		building = 0
		
		# "the following randnum will determine if troops will be added"
		randnum = random.randint(1, 5)
		if (randnum <= 1):
			#"calculate the eligible cities to host the InterTroops (only 1 per Civ in fact : it's a national project)"
			apCityList = py.getCityList()
			for pCity in apCityList:
				#"a city is only eligible for InterTroops if it has a built INTERNATIONAL_CALLING improvement"
				if (pCity.hasBuilding(gc.getInfoTypeForString("BUILDING_EIFFEL_TOWER"))):
					building = 1
					pInterTroopsCity = pCity
					# "Then create new unit"
					gc.getPlayer(pCity.getOwner()).initUnit(gc.getInfoTypeForString("UNIT_MARINE"), pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI)

			if (gc.getPlayer(pCity.getOwner()).isHuman()) and (building == 1):
				# "Popup only for human players"
		
				#"Print on screen International troops arrival"
				sBodyString = CyTranslator().getText("TXT_KEY_INTERTROOPS_ARRIVAL", ()) + " " + pInterTroopsCity.getNameKey() + "."
				SdToolKit.sdEcho(sBodyString)
				#"play a sound when popup appears"
				CyAudioGame().Play2DSound("AS2D_WELOVEKING")
				#"Open the Popup"
				popup = PyPopup.PyPopup(-1)
				popup.addDDS('art/interface/screens/randomevents/intertroops.dds', 0, 0, 256, 256)
				popup.addSeparator()
				popup.setBodyString(sBodyString)
				popup.launch(true, PopupStates.POPUPSTATE_QUEUED)

I still have few problems : :eek:
  • I was forced to suppress the new buiding and the new unit I created specialy for that. The program couldn't find them... So I renamed some existing elements (Eiffel Tower building changed to national project and Marine unit). I thought that building types and unit types are defined in a special place and my new building and unit are not defined there... Is it right or is it a problem with my python ?
  • My program that should run at the beginning of each player turn (onBeginPlayerTurn) runs at the end of the player turn (not really a problem, but I want to understand) : is it normal ? What function should I call to run a program at the beginning of each player turn ?
  • Perhaps linked to the previous line, I can't make the camera look at a plot. It doesn't crash, but it doesn't run...
  • I wanted, in the popup, to have the Civ helm pic superimpose on my custom pic. What ever I do, it appears under (on the line after) my pic. How to do ?
  • I wanted, with SdToolKit, have the city name written with a different color. I tried to insert the Highlight text tag that I found in some XML files, but, not changing color, it writes the tag on screen. Is there an other way to do that ?
  • And, finally, the most important : it runs with CIV4 1.61, but not with Warlords. Is it a problem with the "CvCustomEventManager.py" file that changed (where can I find the new one ?), or is it something else ?...

Well... I think I didn't forget anything. ;)
 
Fabrysse said:
My program that should run at the beginning of each player turn (onBeginPlayerTurn) runs at the end of the player turn (not really a problem, but I want to understand) : is it normal ? What function should I call to run a program at the beginning of each player turn ?

I believe (been a long while) that it was discovered that another function is called at the beginning of the player's turn. I will try to find the function for you, give me a bit...
 
Alright, I couldn't posts where it was said directly, but a look at cyEventManager shows these possibilities:

'BeginGameTurn' : self.onBeginGameTurn,
Not really sure when this is called, but since it's BeginGame I would suspect before any players have moved...
'EndGameTurn' : self.onEndGameTurn, After all players move?
'BeginPlayerTurn' : self.onBeginPlayerTurn, we know it's not this, since you already figured out that it's called between players...
'EndPlayerTurn' : self.onEndPlayerTurn, This would be my educated guess, since it's between players rather than before or after the turn... I would go with this one.

If none of those works, sorry, been a while since my Python has been tested, and even way back when I wasn't a magician, so to speak.
 
About using different colors in messages appearing at the left of screen, I found that example (in a MOD) :
Code:
CyInterface().addMessage(CyGame().getActivePlayer(),True,10,'%s will become unhappy next turn...' %(pCity.getName()),'SND_CITY_REVOLT',1,'Art/Interface/Buttons/General/resistance.dds',ColorTypes(7),pCity.getX(),pCity.getY(),True,True)

How can I have several colors in ColorTypes ? And how can I call them in my mesage string ?
 
Well... I found on my own the way to do my python runs with Warlords.

But I didn't find the way to :
  • Have several colors in text (with or without SdToolKit).
  • Have several images in popup that appear one over the other.
Does anybody know how to do that, please ?
 
Back
Top Bottom