Python help Event to place units on a certain date.

wotan321

Emperor
Joined
Oct 25, 2001
Messages
1,228
Location
NC, USA
Could one of you capable python coders provide us with the code we can plop into our events file that places a unit(s), say a warrior, on a plot (or an adjacent empty plot) on a certain years and month date?

That would be very helpful, and much appreciated.
 
Thanks for the reply, I appreciate the help.

Okay, I looked at that file, and I have a question.

Now, keep in mind I am asking how to do something in Python because I don't know how to program in python myself. The bit of code I have a question about is:

if (iGameTurn >= i190AD and iGameTurn <= i1600AD):
self.spawnUnits( (60, 10), (75, 26), iSkirmisher, 2 + iHandicap, iGameTurn, 5, 4, self.outerInvasion)


If I simply put this in my mod, any mod, say the Sevo Mod or Mylon Mod or any mod.... just simply add these lines, will a unit show up on the map...when? Or are are these lines using variables defined earlier in the file or in another file?

Thanks.
 
Yeah, that's what I thought you would say....

On the outside chance anyone views this thread again, or actually responds to the request for help.... here's the rub for non-python literate types like me.

I know in the programming world, respectable, object oriented programming is where tasks that are made up of sub-tasks are broken down into those subtasks, so you don't have to repeat code in your file. But for those of us who are NOT programmers, we need the whole process in one package.

I am hoping someone will provide me with the code that I can put in whatever the events file is of a mod. The code needs to run on a certain year/month, examine an area around a plot for an empty one, then place on that empty spot a unit from a certain civ.

Maybe that code I posted above does just that, without referencing variables and other modules in that file or other files, but again, I am not educated in python, so I don't know. But the little I do know tells me that all that bit of code will do is give me error messages.

When folks respond to requests for help by telling them "Go look at this or that and mimic it", what you are really saying is "Go learn python". And that is great advice. But I am asking because I don't know python, and simply want someone out of kindness to share some of their superior knowledge. I know that any response and advice on how to get my info is a kind thing, and I am grateful.

But when you don't answer the question, and only say that the answer does exist (though in this case, I believe the solution I am asking for is NOT in Rhyes files), then everyone else who sees the thread will say "Gosh, I see the question is answered and I am not going to type in the simple solution he is asking for".

Yes, I am being an ingrate, and a lazy one at that for not taking the hours to learn python and simply figure it out myself. But I just thought it would be nice if one of the dozens of capable python programmers could take 2 minutes and give me a piece of code that another dozen dozen noobs would LOVE to have. For non-programmers, OOP is not good for us, we need the whole process in one handy unit we can plop into our events file.
 
Code:
def onBeginGameTurn(self, argsList):
	iGameTurn, iPlayer = argsList
	
	if iPlayer == <Insert player number here>:
		if iGameTurn == <Insert the game turn here>:
			iPlotX = <Insert plot X co-ordinate here>
			iPlotY = <Insert plot X co-ordinate here>
			pPlot = CyMap().plot(iPlotX, iPlotY)
			
			bPlotValid = True
			
			for i in range(pPlot.getNumUnits()):
				if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
					bPlotValid = False
					break
					
			if bPlotValid:
				pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)
			else:
				validPlotList = []
				for iX in range(-1, 2):
					for iY in range(-1, 2):
						if iX == iY == 0:
							continue
						bPlotValid = True
						pPlot = CyMap().plot(iPlotX + iX, iPlotY + iY)
						for i in range(pPlot.getNumUnits()):
							if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
								bPlotValid = False
								break
						if bPlotValid:
							validPlotList.append(pPlot)
				
				if len(validPlotList):
					rand = CyGame().getSorenRandNum(len(vaildPlotList), "Random unit plot")
					iPlotX = validPlotList[rand].getX()
					iPlotY = validPlotList[rand].getY()
					
					pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)
Should work. Haven't tested it. It's also pretty rough, could use a cleanup. Make sure you enable python error logging or it won't tell you that it's not working. Assuming you're not planning on having much more python, or you don't need good compatabily just replace the function in CvEventManger.py with this on.

Definately took me more then 2 minutes. It might have been a bit quicker if you didn't want it on a random plot if the current one was occupied, but still more then 2 minutes.

The check checks for enemy units, I didn't know if that's what you wanted or not. Often with this kind of request it's alot easier if you write some psudocode (if this then do this) so that people can understand more easily what you want.
 
wotan321 said:
Yeah, that's what I thought you would say....

On the outside chance anyone views this thread again, or actually responds to the request for help.... here's the rub for non-python literate types like me.

I know in the programming world, respectable, object oriented programming is where tasks that are made up of sub-tasks are broken down into those subtasks, so you don't have to repeat code in your file. But for those of us who are NOT programmers, we need the whole process in one package.

I am hoping someone will provide me with the code that I can put in whatever the events file is of a mod. The code needs to run on a certain year/month, examine an area around a plot for an empty one, then place on that empty spot a unit from a certain civ.

Maybe that code I posted above does just that, without referencing variables and other modules in that file or other files, but again, I am not educated in python, so I don't know. But the little I do know tells me that all that bit of code will do is give me error messages.

When folks respond to requests for help by telling them "Go look at this or that and mimic it", what you are really saying is "Go learn python". And that is great advice. But I am asking because I don't know python, and simply want someone out of kindness to share some of their superior knowledge. I know that any response and advice on how to get my info is a kind thing, and I am grateful.

But when you don't answer the question, and only say that the answer does exist (though in this case, I believe the solution I am asking for is NOT in Rhyes files), then everyone else who sees the thread will say "Gosh, I see the question is answered and I am not going to type in the simple solution he is asking for".

Yes, I am being an ingrate, and a lazy one at that for not taking the hours to learn python and simply figure it out myself. But I just thought it would be nice if one of the dozens of capable python programmers could take 2 minutes and give me a piece of code that another dozen dozen noobs would LOVE to have. For non-programmers, OOP is not good for us, we need the whole process in one handy unit we can plop into our events file.
Well I'm sorry that my help for your question wasn't enough. I'm really not a very good python programmer myself, and I've never actually done what you asked in your question. Believe it or not, the progression in python ablilities for a person does not go from "Not Knowing Python" immediantly to "Python God." But I figured that it would be better for me to say where I've seen what you were asking for before than just not say anything.

I'm glad that TGA came along to show something more useful :)



Oh and thank you very much for that code snippet TGA. That little process for finding a valid plot is very interesting and has helped me. Maybe you could post it in the Sample Python code thread?
 
Wow, this whining stuff really works......

TGA noted:
Often with this kind of request it's alot easier if you write some psudocode (if this then do this) so that people can understand more easily what you want.

Yes, that is a good point. I was embarassed to use a Civ2 scripting example, but that would have helped.

..and Gunner, thanks to you too, I really do appreciate your desire and action to help me. Its your attitude, like TGA's, that repeatedly impress me with the Civ community.

Yes, learning python is something I am working on when I can... I have reached that "knows enough to be dangerous" stage, where the imporant value of "backups" is stressed by each painful lesson. Its gonna take some time and practice.... I appreciate your insights and encouragement.

To both of you, much thanks.

...I guess I should try the code before I get all gushy....<g>.
 
Gunner said:
Believe it or not, the progression in python ablilities for a person does not go from "Not Knowing Python" immediantly to "Python God."


True, but there seems to be something missing here in the learning process. There are great Python tutorials on this site and there are awesome Mods, sample python scripts and Civ4 library references. But what's missing is a tutorial on 'Civ4 Python'. For example, even a tutorial starting with printing 'Hello World!' on the Civ4 in-game screen would be nice. I would bet that most people wouldn't be able to do it even after going through the 'regular' Python tutorials. It would be nice to start a tutorial with the 'Hello World!' type message, then progress up slowly to more difficult concepts like the code in this request. Just a thought. :)
 
Hey wotan, sorry about getting kinda angry there. I obviously misinterpreted your tone from that post I had quoted. Plus I was posting early in the morning, which is always a bad idea :crazyeye:

Hope everything works out!


@Thorn
You might want to check out TGA's tutorial for Civ4 in his sig. Its not quite as basic as you were describing, but I think its a godsend for anyone looking to learn python for Civ4.
 
The Great Apple said:
Code:
def onBeginGameTurn(self, argsList):
	iGameTurn, iPlayer = argsList
	
	if iPlayer == <Insert player number here>:
		if iGameTurn == <Insert the game turn here>:
			iPlotX = <Insert plot X co-ordinate here>
			iPlotY = <Insert plot X co-ordinate here>
			pPlot = CyMap().plot(iPlotX, iPlotY)
			
			bPlotValid = True
			
[b]			for i in range(pPlot.getNumUnits()):
				if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
					bPlotValid = False
					break
					
			if bPlotValid:
				pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)
			else:
				validPlotList = []
				for iX in range(-1, 2):
					for iY in range(-1, 2):
						if iX == iY == 0:
							continue
						bPlotValid = True
						pPlot = CyMap().plot(iPlotX + iX, iPlotY + iY)
						for i in range(pPlot.getNumUnits()):
							if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
								bPlotValid = False
								break
						if bPlotValid:
							validPlotList.append(pPlot)
				
				if len(validPlotList):
					rand = CyGame().getSorenRandNum(len(vaildPlotList), "Random unit plot")
					iPlotX = validPlotList[rand].getX()
					iPlotY = validPlotList[rand].getY()
					
					pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)[/b]


This is good, but I wonder if you can't just put the unit on the plot, then check if it's a valid plot and if not use pUnit.jumpToNearestValidPlot()
 
That would be a much better method. I don't check the domains or anything here so you could end up with a land unit in water or something similar.

Except... if you initiate a unit on a plot with an enemy unit on it kills the enemy unit IIRC. You have to find the plot before initiating the unit.
 
TGA, thanks again. What needs to be amended in your earlier code to place multiples of the same unit?

..and Gunner, I apologize for my snarky and sarcastic tone, I was simply being impatient. Your help is much appreciated. Thanks again to all of you who have offered information and advice.
 
The Great Apple said:
That would be a much better method. I don't check the domains or anything here so you could end up with a land unit in water or something similar.

Except... if you initiate a unit on a plot with an enemy unit on it kills the enemy unit IIRC. You have to find the plot before initiating the unit.

Ah, you're right.

That's too bad they didn't make the checking for a valid plot a seperate function to use.
 
Instead of

pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)
Code:
for i in range(<Number of units>):
	pUnit = gc.getPlayer(iPlayer).initUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>", iPlotX, iPlotY, NO_UNITAI)
should work.

I might have a fiddle around and make it so that it checks for a proper valid plot.
 
Gunner said:
@Thorn
You might want to check out TGA's tutorial for Civ4 in his sig. Its not quite as basic as you were describing, but I think its a godsend for anyone looking to learn python for Civ4.


Yes, that is a great tutorial and very useful for learning. But what I was wondering if there were any tutorials that would walk you through an actual mod example. Just something as basic as- If a Warrior unit dies anywhere on the map, then have a message popup that says 'A warrior has been lost...'.
The tutorial would describe step by step what files need to be changed/created, what the lines of code do, what directories to put the files, etc. etc. At the end of the tutorial you should be able to actually run the mod and show the desired output. A couple of tutorials like this getting a little more advanced each time would be really helpful. Of course, I also realize that it would be time consuming for someone to do that :p
 
I wonder if this would work. It should, but then again you might want to wait till TGA or someone approves it ;)

Code:
def makeUnit(self, iUnit, iPlayer, tCoords, iNum): #by LOQ
                'Makes iNum units for player iPlayer of the type iUnit at tCoords.'
                for i in range(iNum):
                        player = gc.getPlayer(iPlayer)
                        player.initUnit(iUnit, tCoords[0], tCoords[1], UnitAITypes.NO_UNITAI)

def onBeginGameTurn(self, argsList):
    iGameTurn, iPlayer = argsList
    
    if iPlayer == <Insert player number here>:
        if iGameTurn == <Insert the game turn here>:
            iPlotX = <Insert plot X co-ordinate here>
            iPlotY = <Insert plot X co-ordinate here>
            pPlot = CyMap().plot(iPlotX, iPlotY)
            
            bPlotValid = True
            
            for i in range(pPlot.getNumUnits()):
                if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
                    bPlotValid = False
                    break
                    
            if bPlotValid:
                pUnit = self.makeUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>"[B])[/B],gc.getPlayer(iPlayer),(iPlotX, iPlotY), "<Insert number of units you want here>")
            else:
                validPlotList = []
                for iX in range(-1, 2):
                    for iY in range(-1, 2):
                        if iX == iY == 0:
                            continue
                        bPlotValid = True
                        pPlot = CyMap().plot(iPlotX + iX, iPlotY + iY)
                        for i in range(pPlot.getNumUnits()):
                            if gc.getTeam(pPlot.getUnit(i).getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
                                bPlotValid = False
                                break
                        if bPlotValid:
                            validPlotList.append(pPlot)
                
                if len(validPlotList):
                    rand = CyGame().getSorenRandNum(len(vaildPlotList), "Random unit plot")
                    iPlotX = validPlotList[rand].getX()
                    iPlotY = validPlotList[rand].getY()
                    
                pUnit = self.makeUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>"[B])[/B],gc.getPlayer(iPlayer),(iPlotX, iPlotY), "<Insert number of units you want here>")
You have to make sure that the two definitions are in the same class.

Also, don't you need a closing parenthese for this line?
gc.getInfoTypeForString("<Insert unit name as in XML here>")

Edit: Saw that TGA beat me to it, and his looks a lot smaller too. It would still be great if someone told me if my way would work :)
 
Almost. You're passing a player pointer to the function where it wants a player ID:

self.makeUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>"), iPlayer, (iPlotX, iPlotY), "<Insert number of units you want here>")

is better.

Also, the function above doesn't return anything, so you'll want to remove the "pUnit =" thingy - that was just in case he wanted to do something with the unit.
 
Okay, so if I want to put in 2 different (or 3 or 4) different unitclasses, I simply repeat that line

self.makeUnit(gc.getInfoTypeForString("<Insert unit name as in XML here>"), iPlayer, (iPlotX, iPlotY), "<Insert number of units you want here>")


but put in the unique unitclass name.

In that way I could lay down a warrior, 2 pikeman and a scientist on a certain date?

This is great info, if I hadn't mentioned that already.....

Thanks.
 
Okay, I came home and tried to implement this.

A couple of basic questions.

1. What file do I put this in if I am creating my own mod?
\Mods\TestMod\Assets\Python\CvEventManager.py

2. In the line
if iGameTurn == <Insert the game turn here>:
are we talking about the year in the game, as in 3800BC, or the game turn 4?

3. So, after the discussion in previous posts about what is the better code, what is the final product?

Again, big globs of thanks.
 
Back
Top Bottom