Python help

fallador

Chieftain
Joined
Jan 4, 2006
Messages
19
I don't know if it's possible but could you have a python event that gets the production, food and commerce values of the plot when you build a route. Then, depending on these values, a certain number of units spawn.

Also, while I'm here, what xml file do you need to change to set when the animals and barbarians start to spawn and how strong they are.

Also also, can you have buildings that disappear a few turns after being built.
 
Ok, I am wingin'it here, so you'll probably need to do more work on this.

:P I love canabalizing code: This is for the cvEventManager.py

Code:
	def onBuildingBuilt(self, argsList):
		'Building Completed'
		pCity, iBuildingType = argsList
		game = CyGame()

		iBarracks = gc.getInfoTypeForString('BUILDING_BARRACKS')
		# assuming you wanna destroy the barracks

		iActivePlayer = CyGame().getActivePlayer()
		pPlayer = gc.getPlayer(pCity.getOwner())
		iOwner = pCity.getOwner()
		iX = pCity.getX()
		iY = pCity.getY()
		pPlot = CyMap().plot(iX,iY)
		iBarracks = gc.getInfoTypeForString('BUILDING_BARRACKS')
		iCityID = pCity.getID()
		
		if iBuildingType == iBarracks:
			if (not CyGame().isNetworkMultiPlayer()) and (not iOwner == iActivePlayer): 
				#check for MP or else everybody active -> snyc loss
				pCity.setHasRealBuilding(iBarracks, False)
					if (gc.getTraitInfo(iTrait).getTextKey() == 'TXT_KEY_TRAIT_PASSIVE'):
					# I have a custom trait called Passive for upper asian civs
						if pCity.isHasRealBuilding(iBarracks):
							self.unrest[iCityID] = 5

			if self.unrest[iCityID] and self.unrest[iCityID] > 0:
				self.unrest[iCityID] -= 1
			else:
				pCity.setHasRealBuilding(iBarracks, False)

build the barracks, unrest for 5 turns, auto barrack destruction
 
Cool, thanks. That looks pretty much like what I wanted but doesn't that code only run when you build the barracks. I would have thought that this part would need to run every turn.
Code:
if self.unrest[iCityID] and self.unrest[iCityID] > 0:
				self.unrest[iCityID] -= 1
			else:
				pCity.setHasRealBuilding(iBarracks, False)
 
That's true, it will only run when the building's built.

I think that there's something that keeps track of when a building was built anyway...

pCity.getBuildingOriginalTime(iBuildingNum)

will return the year the building was created.

So, you could do something like this in onEndPlayerTurn:

Code:
def onEndPlayerTurn(self, argsList):
	'Called at the end of a players turn'
	iGameTurn, iPlayer = argsList

	iBuildingNum = gc.getInfoTypeForString("BUILDING_BARRACKS")

	# Gets the tuple of (city object, next city ID)...
	# Returns pCity as None when we have no more cities to check
	pPlayer = gc.getPlayer(iPlayer)
	pCity, iNextCity = pPlayer.firstCity(False)

	while (pCity):
		if (pCity.hasBuilding(iBuildingNum) ):
			iBuildYear = pCity.getBuildingOriginalTime(iBuildingNum)
			iFiveTurnsAgoYear = gc.getGame().getTurnYear(iGameTurn)
			
			# If five turns have elapsed
			if (iBuildYear <= iFiveTurnsAgoYear):
				pCity.setHasRealBuilding(iBuilding, False)
				pCity.setFreeBuilding(iBuilding, False)

		pCity, iNextCity = pPlayer.nextCity(iNextCity, False)

I just wrote that into the browser, so be warned I haven't tested it for anything.

Edit: Also, there's another event function called "onRouteBuilt". So, every time you build a route, you can check the plot using the various functions found here: API and use pPlayer.initUnit (check out the API page to see the arguments).

Also, Civ4HandicapInfo has some barbarian tags in it.
 
I like Gerikes solution alot. The only recommendation I would offer would be to put it in cityDoTurn instead of onEndPlayerTurn, so you don't have to parse all of the city's again.

onEndPlayerTurn is a very badly named function because you would assume it runs at the end of your turn. It actually runs as the last maintenance event before the player is allowed to start with all his decisions for the turn. So it kicks before you move units or anything.
 
Woah, I'm really too good at procastinating, I've been meaning to do this for ages. Anyway, could someone please look through this and help me with it.
Code:
def onRouteBuilt(self, argsList):
		'Route Built'
		iRoute, iX, iY = argsList
		pPlot = CyMap().plot(iX,iY)
		pPlayer = gc.getPlayer(pPlot.getOwner())
                if(iImprovement==gc.getInfoTypeForString('ROUTE_PRODUCTION')):
			player = pPlot.getOwner()
			pPlayer = gc.getPlayer(player)
                        production = [B]{code for getting production value of plot}[/B]
                        if production = 1:
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
                        elif production = 2:
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
			elif production = 3:
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
                        	newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI)
		if (not self.__LOG_IMPROVEMENT):
			return
		CvUtil.pyPrint('Route %s was built at %d, %d'
			%(gc.getRouteInfo(iRoute).getDescription(), iX, iY))
 
i can't fix all your code but perhaps this will help you :

1 : iImprovement is not defined , not sure this test is usefull .

2 : you should begin with a test to know if the plot is owned : if pPlot.isOwned() (not tested , but i think the value returned by pPlot.getOwner() is -1 if you build a route outside cultural border )

3 : to calculate the production yield , you may try pPlot.calculateYield(YieldTypes.YIELD_PRODUCTION, BOOL bDisplay) , but i don't know for what bDisplay is made for ?

4 : instead of the serial of test for initUnit you can make :
Code:
for id in range(production):
          newUnit = pPlayer.initUnit(gc.getInfoTypeForString('UNIT_PRODUCTION'), iX, iY, UnitAITypes.NO_UNITAI)

Tcho !
 
Thanks for all that :
1. Yeah, thats probly just me being unco while copy and pasting, it should be iRoute

2. Why would I do that. The whole point of this is so it could be outside borders.

4. Yeah, I knew there was a better way but I wasnt good enough at python to write it
 
not sure i've understood , but if you want that the event trigger outside border :

outside borders : pPlot.getOwner() return -1 so pPlayer = gc.getPlayer(-1) is a fantom player -> probably pPlayer.initUnit(.. will cause a bug .
 
Oh right, I get you. So how would you get the player when it triggers outside the borders. I've tried a few things, such as the unit owner and the active player, but I haven't been able to get anything to work. I also haven't been able to get pPlot.GetYield() or pPlot.CalculateYield() to work.
 
fallador said:
Oh right, I get you. So how would you get the player when it triggers outside the borders. I've tried a few things, such as the unit owner and the active player, but I haven't been able to get anything to work. I also haven't been able to get pPlot.GetYield() or pPlot.CalculateYield() to work.

There's no way to actually get what player owns the plot, because no player owns the plot. The question you have to answer is what exactly happens when a route is built on a plot that is unowned.

Edit: Wait, I see what you mean. If you still want to create units (aka finding out what player "finished" the route), you might want to look through all the units on the plot. I had to deal with a similar situation in Civcraft, where I wouldn't know who would actually have finished something, considering you can't just check the units on the plot as their might be units from multiple teams. You can probably go through all the units, and look for the ones that are building the route (checking what mission they have, since the unit's mission isn't reset until AFTER the function is called). This will be pretty acurate, but not COMPLETELY acurate. To be completely accurate, you'd have to go into the SDK and find where the unit passes it's build info to the plot to finish, then put your code there. However, I think you're better off just looking at the units of the plot and guessing which one finished the route. You'll have 99% of cases covered.
 
I'm not actually wanting to find out the owner of the plot, I just need whoever built the route. Since when the routes built its not connected to any player or unit I'm finding it pretty difficult.

Edit: Oh, I didn't notice your edit. Thanks, I thought it might be something like that but I was hoping there would be an easier way. And, im feeling stupid but I can't find a way to get the mission of a unit in the API.
 
Gah, thats it, I give up. I officially suck at python. Could someone just tell me the code for this event because I really dont think I can do it.
 
Well, what you have is more than a python issue: it's a gameplay issue. If you want something to happen to someone who has built a route, you have to figure out who you want to consider as the "builder" of the route. There might be a case where a route is built without having a worker unit build it (when a city get's placed comes to mind, since it automatically puts the most recent route (road or RR) on the plot automatically).

Here are a few ways you can go about it:

1.) Look at the first unit on the plot.

Code:
def onRouteBuilt(self, argsList):
	'Route Built'
	iRoute, iX, iY = argsList

	# The player who we will assume built the route
	# Set to -1 to start. If it's still -1 at the end, we didn't really ever find
	# out who built it.
	iPlayer = -1

	# Check if there was actually a unit there. I'm not sure if there will ever
	# be a case for this, but we should check anyway.
	pPlot = CyMap().plot(iX, iY)
	if (pPlot.getNumUnits() > 0):
		# Get the first unit on the plot.
		iPlayer = CyMap().plot(iX, iY).getUnit(0).getOwner()

	# Find out if we found a player.
	if (iPlayer != -1):
		# Do what we want to do.
		pPlayer = gc.getPlayer(iPlayer)
		pPlayer.whatever....

2.) Look at the first unit building a road.

Now, this will suppose that if there are multiple units on the plot that the first unit is the guy who built it. So if there's a warrior of player 1 on the plot and an army of workers from player 0 building the road, then there's a chance that using getUnit(0) will return the warrior. So, we should probably do this instead:

Code:
	def onRouteBuilt(self, argsList):
            'Route Built'
            iRoute, iX, iY = argsList

            # iPlayer is the player who we will assume built the route
            # Set to -1 to start. If it's still -1 at the end, we didn't really ever find
            # out who built it.
            iPlayer = -1

            # Go through all the units on the plot, and find the first one that was
            # building a route.
            pPlot = CyMap().plot(iX, iY)
            for iI in range( pPlot.getNumUnits() ):
                print "Looping player %d" % iI
		pGroup = pPlot.getUnit(iI).getGroup()

		iMissionType = pGroup.getMissionType(0)

                # We have to determine if they're actually building a route
                bBuildingRoute = False
		if (iMissionType == int(MissionTypes.MISSION_ROUTE_TO) ):
                    bBuildingRoute = True
                elif (iMissionType == int(MissionTypes.MISSION_BUILD) ):
                    iBuild = pGroup.getMissionData1(0)
                    # Make sure what they're building is a route, they might be building a mine or something.
                    if ( gc.getBuildInfo(iBuild).getRoute() != RouteTypes.NO_ROUTE ):
                        bBuildingRoute = True

                # This was the first unit on the plot that was building a route.
                # In most cases, the owner of this route is the person who "built" the route.
                if bBuildingRoute:
                    iPlayer = pGroup.getOwner()
                    # Break out of the for loop that is going through all the units
                    break

            # Do what you want now with the player.
            if (iPlayer != -1):
                pPlayer = gc.getPlayer(iPlayer)
                pPlayer.doWhatever()

Realize that unless you keep track of how many times a specific player has a unit work on the plot, there's no way of determining who hit the final nail or who worked on the route more. However, the above way of doing it will cover most cases.

Now, note that this takes nothing about who owns the plot into consideration, which you could easily find out with pPlot.getOwner() (remembering to check for if -1 is returned for a plot not owned by anyone).

Good luck.
 
Back
Top Bottom