BarbarianCiv stuff

OK, I have need of some more help. My goal here is to get BarbarianCiv to check when it creates a new minor civ for other barb cities nearby. Based on an algorithm then it will determine whether or not to add those barbarian cities to the new civ as well, thus makign Barb civs more powerful. Does anyone have an idea on how to go about doing that?
 
I'd loop through all pther barbarian cities, and check plot distance.

Though, I'm pretty sure I once saw a barbciv getting more than one city. The createMinorCiv() function actually can take more than one city as argument, but it is always called with a single city (at least in Legends of Revolutions, which I'm viewing ATM). So there is maybe a mod anywhere where it is called with more than one city.

EDIT: it seems it IS actually done, in settleMinorCiv() (when the barb civ settles down). I found some information about that here.
 
I have seen a multiple city civ spawn from barbarians in C2C, actually. It was pretty surprising. One barb city was clearly about to turn into some civ so I figured it was time to go take the city. I was just sending off a small, but not too small, army to do it when suddenly they got organized into some civilization and took 2 other barb cities with them so I was not facing a 1 city civ, I was facing a 3 city civ without enough army to take all 3 cities. (So I took a different barb city that happened to be on the way there and then waited there for reinforcements before going after the new civ.)

But that was the only time I ever noticed it do that. On the other hand, having come across a few civs that must have spawned from barb cities that had more than 1 city it is possible that it has happened in some of my games out of my sight rather than them capturing another barb city or two, like it could also be.
 
I have seen a multiple city civ spawn from barbarians in C2C, actually. It was pretty surprising. One barb city was clearly about to turn into some civ so I figured it was time to go take the city. I was just sending off a small, but not too small, army to do it when suddenly they got organized into some civilization and took 2 other barb cities with them so I was not facing a 1 city civ, I was facing a 3 city civ without enough army to take all 3 cities. (So I took a different barb city that happened to be on the way there and then waited there for reinforcements before going after the new civ.)

But that was the only time I ever noticed it do that. On the other hand, having come across a few civs that must have spawned from barb cities that had more than 1 city it is possible that it has happened in some of my games out of my sight rather than them capturing another barb city or two, like it could also be.

Yeah. My goal here is to make barb civs be on average 5 or 6 cities big when they spawn, as in my current game I have about 20 OPM civs which constantly waste my time with diplomatic requests and add extra end-turn times.

I'm still trying to understand all of the BarbCiv python though, there is quite a lot of it.

Edit:

I think this is the code for adding more cities to a new barb civ.

Code:
    iNumBarbDefenders = gc.getHandicapInfo( game.getHandicapType() ).getBarbarianInitialDefenders()
    pyBarbPlayer = PyPlayer( gc.getBARBARIAN_PLAYER() )
    barbCityList = pyBarbPlayer.getCityList()

    for barbCity in barbCityList :
      pBarbCity = barbCity.GetCy()

      if( pBarbCity.area().getID() == capital.area().getID() ) :
        if( pBarbCity.getPreviousOwner() == -1 ) :
          iDist = plotDistance( capital.getX(), capital.getY(), pBarbCity.getX(), pBarbCity.getY())
          iDist2 = gc.getMap().calculatePathDistance( capital.plot(), pBarbCity.plot() )
          iBarbCityRand = game.getSorenRandNum(iDist*iDist, "Give barb city")
          if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Distance to barb city %s is %d (path %d, rand %d"%(pBarbCity.getName(),iDist,iDist2,iBarbCityRand))

          if( iDist < 10 ) :
            if( 20 > iBarbCityRand ) :
              pBarbCityPlot = pBarbCity.plot()
              if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Adding extra barb city %s at %d, %d"%(pBarbCity.getName(),pBarbCity.getX(),pBarbCity.getY()))
              pBarbCityPlot.setOwner( newPlayer.getID() )
              self.setupFormerBarbCity(pBarbCityPlot.getPlotCity(), newPlayer.getID(), iBestDefender, int(iNumBarbDefenders*self.militaryStrength + 0.5))

That algorithm looks rather timid in finding new barbarian cities and adding them, so I think I'll write a new one based on how far away the city is and how populous it is.

Edit2:

Does this algorithm look reasonable? (Note that it is only replacing the second part of the original algorithm.)
Code:
		  iCityJoinFactor = (pBarbCity.getPopulation() * iBarbCityRand * 10) / iDist
		  if (iCityJoinFactor >= 4) :
			pBarbCityPlot = pBarbCity.plot()
			if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Adding extra barb city %s at %d, %d"%(pBarbCity.getName(),pBarbCity.getX(),pBarbCity.getY()))
				pBarbCityPlot.setOwner( newPlayer.getID() )
				self.setupFormerBarbCity(pBarbCityPlot.getPlotCity(), newPlayer.getID(), iBestDefender, int(iNumBarbDefenders*self.militaryStrength + 0.5))
The only issue I have is that I'm not certain what sort of numbers to expect form getSorenRandNum, as the Apolyton site isn't too detailed about it.
 
I don't think your algorithm is very good.

The getSorenRandNum(N) returns a number from 0 to N-1 (so there are N choices starting with 0). It is currently returning a number from 0 to iDist^2 - 1. The bigger the value of iDist, the bigger the random number can be (by a lot, since it is using iDist squared). Therefore your current iCityJoinFactor equation will, on average, give larger values for cities that are farther away.

I would suggest two things. First, add 1 to iBarbCityRand so it goes from 1 to iDist^2, so there is no possibility of a 0. Second, for your iCityJoinFactor start testing with something more like this:
iCityJoinFactor = (pBarbCity.getPopulation() * 10) / iBarbCityRand
(now you see why making it so it can't be 0 is good).

I also noticed that it calculates an iDist2 value that is the actual path distance. In the original I suspect there is an error and the " if( iDist < 10 )" test should have been using iDist2, but it may just be left over from some earlier version of the script. As it is, it is wasting time calculating the path distance (which naturally uses the pathfinder, which is not the fastest operation in the universe) and then not even using it (at least not in the code you show).

I would therefore suggest either removing iDist2 or using it. You could, for example, try something like "if (iCityJoinFactor >= 4) and (iDist2 <= 10) :" to limit the actual travel distance to the additional cities to make sure they are in a potentially cohesive group - including cities on the other side of a large bay where the straight line distance is much shorter than the actual path a unit has to take to get there is probably not a good idea since the new civ won't be able to shift units to/from that city very quickly and may have to go through some other civ's territory to get there. You could probably bump that "10" up in later eras, partially allowing for roads that actually increase movement rates, perhaps by adding the current era number to it. It could also be scaled by map size in some way.

You also might want to sort the list by distance, closest first, and then apply a cutoff to stop trying to add cities if the total reaches some value so that the new civ isn't too big compared to the existing civs. If the "regular" civs are, for example, all in the 4-8 city range, spawning a 10 city civ out of barbarians could be seen as a bad thing. So limiting it to having perhaps something like a number of cities that is not greater than the average number of cities for the existing civs could be good.

It's pretty easy to come up with an algorithm for things like this. It's a bit trickier to come up with a good one...
 
@God-Emperor: Thanks much for helping me with this, Python is certainly not my strong point.

One more question. Does CyGame.getMaxTurns() return the total number of turns for a particular gamespeed (whichever one is in use in that game)?
 
It appears that the number returned by getMaxTurns will only be set in the DLL if the time victory condition is turned on. It looks like if that VC is not active it should return 0, but if it is active it should return the turn number of the turn when that VC happens.

The CyGame.getEstimateEndTurn function appears to return the actual turn number you get from adding up all the increments (as they are called in the DLL code) in the game speed info, where it specifies X turns at Y months per turn for each of the specified set of "increments" - this function returns is the sum of all those X values. This is independent of any victory conditions being active.
 
It appears that the number returned by getMaxTurns will only be set in the DLL if the time victory condition is turned on. It looks like if that VC is not active it should return 0, but if it is active it should return the turn number of the turn when that VC happens.

The CyGame.getEstimateEndTurn function appears to return the actual turn number you get from adding up all the increments (as they are called in the DLL code) in the game speed info, where it specifies X turns at Y months per turn for each of the specified set of "increments" - this function returns is the sum of all those X values. This is independent of any victory conditions being active.

OK, thanks, that is what I wanted to do (more specifically, get the percent of the game that had gone by so far).
 
Back
Top Bottom