Revolution: with BarbarianCiv, Rebellion, AIAutoPlay

OK, I've tested this some more, and I can't get it to create a settler if no city exists. My code, roughly, is:

Code:
	def onCityBuilt(self, argsList) :
		city = argsList[0]
		iX = city.getX()
		iY = city.getY()

		iXX = iX-4
		iYY = iY-4
		oPlot = CyMap().plot(iXX, iYY)
		if oPlot.getPlotType() == 2:
			CvUtil.pyPrint("Land -- Good")
		

		if (city.getOwner() == CyGame().getActivePlayer()):
			success = game.createNewPlayer(1, 1, 1, iXX, iYY )
			if( not success ) :
				CvUtil.pyPrint("  BC - FAILED to create civ at X %d, Y %d"%(iXX,iYY))
                		return
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))
(Obviously this is provisional code as this will only work once, for the first city built, but even that didn't work. Note that of course when I call your function at iX, iY it hands control over to the resurrected civ and I die...)
 
Padmewan said:
OK... After screwing around with this for a while I've "discovered" (duh) that you can't use createNewPlayer to add MORE civs than is set up at the beginning of the game.

jdog, this mod is AWESOME -- and I would love it even more if you figure out how to get the total number of civs to "stretch" (up to the max of 18 at a time, of course)!!!

Glad you like it! Unless I'm misunderstanding you, createNewPlayer should add new civs that were never there (up to 18 of course) and I'm puzzled why it's not working for you. However, if the slot (playerIdx) you're trying to place them in is occupied by a live civ, it will not let you create a civ there. There are a multitude of other reasons it can fail, including passing an invalid starting position for the new civ. So I'm not sure why it wasn't working for you, as it does create a new player from scratch when barbarian civs settle down. What are you calling the function with? (Edit: Just saw your code, will check out).

If you would be willing to try a couple more times after setting (in the CivIV.ini):

LoggingEnabled = 1

And if it still doesn't work, post the sdkDbg.log from My Games/Sid's CIV/Logs I'll have a look and see what's going wrong. It should do just what you're asking for!!!

That being said, the current changePlayer function is, shall we say, rough around the edges and I'd wait for the next version where I've fixed (most) of the trait and graphics changing problems.
 
Impaler[WrG] said:
This gives me an idea,

I have always found it very silly that Nations like America exist from 4000 BC. With this Civ changing ability you have created it should be possible to have "Modern" nations spawn at various points in the game, infact we could thing of it as an upgrade much like units have.

Heres the plan, each Civ could have <RevolutionCivilization> which references another Civ, it also has a Tech <RevolutionTech> when the player reaches this technology they get a popup asking them if they wish to start a Revolution and if so to choose their new leader from among thouse avalible in the new Civ. They get a turn of Anarchy and are converted to the new Civ/Leader combo.

Multiple such Revolutions could occur through the game and their could be multiple branchings from each Civ, say for example England could spawn America, Australia and Canada at various points. Russia would become the Soviet Union and then go back to being Russia. Different Civs could both spawn the same Civ say for example the Cherroke could also spawn America (if the English haven'r already done so, I am wonding if their is any protection on your function to prevent 2 instances of the same Civ in the game?)

P.S. Would you like to have this mod slated for inclusion in the Civ4CoreCommunity project?

Certainly some intersting ideas! The changePlayer function will (currently has bugs: won't replace the flags for units the player could see at the time of civ change for example) in the not to distant future be able to do exactly what you propose. I hadn't thought of adding in the option for a whole civ to switch over to another civ type in the general game ... I was thinking of it mainly for using a different civ in the slot previously occupied by a now dead civ and then reincarnating them.

The SDK code will not stop you from creating multiple instances of the same civ, or using incongrous leaders (like Sid ;) ), that kind of limit is left to the Python code calling the SDK function.

"Eventually" I would definitely like to add this to the community project, it's all basically "resource" functions ... functions you can use to change the game, but if you don't won't alter anything, so it seems like a natural fit.
 
success = game.createNewPlayer(1, 1, 1, iXX, iYY )

Are you alone in the world? Otherwise slot 1 will be occupied and you won't be able to start a civ there ... other than that it looks alright. I'm not as confident of the settler giving code as the city giving code, only tested it a handful of times, but regardless if it gets to that point and the settler giving goes awry you'll get a message saying "so and so civilization has been destroyed!" If that happens, mea culpa, but you can also (now that the civs been setup) give them a unit using Python and know that they exist ...
 
jdog5000 said:
Glad you like it! Unless I'm misunderstanding you, createNewPlayer should add new civs that were never there (up to 18 of course) and I'm puzzled why it's not working for you. However, if the slot (playerIdx) you're trying to place them in is occupied by a live civ, it will not let you create a civ there. There are a multitude of other reasons it can fail, including passing an invalid starting position for the new civ. So I'm not sure why it wasn't working for you, as it does create a new player from scratch when barbarian civs settle down. What are you calling the function with?
OK, now I understand what "slot" means. The first time I tried this, maybe I was lucky in assigning the exact slot that was killed.

Let's say game.countCivPlayersEverAlive() is 14
Can this mod create a new civ at slot 15?

I just ran a test and the answer seems to be "yes"...
 
jdog5000 said:
Are you alone in the world? Otherwise slot 1 will be occupied and you won't be able to start a civ there ... other than that it looks alright. I'm not as confident of the settler giving code as the city giving code, only tested it a handful of times, but regardless if it gets to that point and the settler giving goes awry you'll get a message saying "so and so civilization has been destroyed!" If that happens, mea culpa, but you can also (now that the civs been setup) give them a unit using Python and know that they exist ...

OK, now that I have slots working properly, I am now 75% sure that this mod does not give the civ a settler. It will hand over control of an existing city, but if no city exists, the function returns as failed. Here's are two tries:

WORKS (hand over the newly-built city):
Code:
	def onCityBuilt(self, argsList) :
		city = argsList[0]

		iX = city.getX()
		iY = city.getY()

#		iSlot = self.iSlot

		iSlot = game.countCivPlayersEverAlive()+1

		if (city.getOwner() == CyGame().getActivePlayer()):
			success = game.createNewPlayer(iSlot, 1, 1, iX, iY )
			if( not success ) :
				CvUtil.pyPrint("  BC - FAILED to create civ at X %d, Y %d"%(iXX,iYY))
                		return
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))
DOESN'T WORK (pick a plot that's not a city) :
Code:
	def onCityBuilt(self, argsList) :
		city = argsList[0]

		iX = city.getX()
		iY = city.getY()

#		iSlot = self.iSlot

		iSlot = game.countCivPlayersEverAlive()+1

		iXX = iX-4
		iYY = iY-4
		oPlot = CyMap().plot(iXX, iYY)
		if oPlot.getPlotType() == 2:
			CvUtil.pyPrint("Land -- Good")
		if (city.getOwner() == CyGame().getActivePlayer()):
			success = game.createNewPlayer(iSlot, 1, 1, iXX, iYY )
			if( not success ) :
				CvUtil.pyPrint("  BC - FAILED to create civ at X %d, Y %d"%(iXX,iYY))
                		return
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))
 
Now this is interesting: it looks like the game engine resurrects, then kills, the new civ (relevant part in bold):
PY:City Built Event: Rome
PY:Land -- Good
PY:player 6's alive status set to: 1
PY:player 6's alive status set to: 0
PY: BC - FAILED to create civ at X 22, Y 9
23 SCREEN TURNED ON
Is it possible that a civ with no cities is considered "dead," even if it has settlers, with the exception of a starting settler?
 
Padmewan said:
Is it possible that a civ with no cities is considered "dead," even if it has settlers, with the exception of a starting settler?
I think this is the case only after the first 10 turns, unless you've changed the python that controls this.
 
The Great Apple said:
I think this is the case only after the first 10 turns, unless you've changed the python that controls this.
I hadn't. So this may be a bug in CyGame.createNewPlayer in terms of creating a settler when no city exists to transfer to the new or resurrected Civ. (I have one more experiment to run, which it that I set both civ and leader to "1," but "1" corresponds to Arabia, which has only 1 leader, so maybe leader should be "0." I'm just being lazy in my testing of this mod)

jdog, this is an awesome expansion and I look forward to all the exciting new features you're planning. For my own mod, I hope to use this to be able to guarantee that a particular civ shows up in the game.
 
After flailing a little more, this might be a workaround?
Code:
if (city.getOwner() == CyGame().getActivePlayer()):
	success = game.createNewPlayer(iSlot, 1, 1, iX, iY )
	if( not success ) :
		pyNewPlayer = PyPlayer(iSlot)
		pyNewPlayer.initCity(iX,iY)
...it's working for me :)
 
Padmewan said:
Now this is interesting: it looks like the game engine resurrects, then kills, the new civ (relevant part in bold):

Is it possible that a civ with no cities is considered "dead," even if it has settlers, with the exception of a starting settler?

The create settler code is not currently working, I will fix it soon. Any civ with no cities or units is considered dead and promptly set to dead (duh). A civ that loses its last city (and you don't have "Complete Kills" on) will be set to dead. However, a civ with only a unit but with the foundedFirstCity flag set to false will not be killed. So, once I fix the give settler portion the player will be created and not killed off ...
 
Padmewan said:
OK, now I understand what "slot" means. The first time I tried this, maybe I was lucky in assigning the exact slot that was killed.

Let's say game.countCivPlayersEverAlive() is 14
Can this mod create a new civ at slot 15?

I just ran a test and the answer seems to be "yes"...

All the data structures (slot, civ type, leader type, etc) start at 0. So, "normally" the human player is in slot 0 and if you have 7 civs in the game (including you), they'll occupy slots 0 through 6. Then the mod could create a new civ in any slot from 7 through 17.

I'll edit the initial post to make the calling convention for the function more clear put here's what the things mean:

createNewPlayer( playerIdx, civType, leaderType, ix, iy)

playerIdx is the slot number for the player or civ. When the game starts these are set up starting at 0, up to (num civs in game - 1). Since it starts at 0, the highest allowed slot number is 17, and the barbarian state occupies slot 18.

civType is the index of the civ description in the XML code. I think America is 0, maybe Arabia is 1, and after the normal civs I think 18 is the Minor civs and 19 is the Barbarian civ.

leaderType is also an index from the leader XML code, I think Sid (barb leader) is 0, Washington is 26. You are allowed to specify any leader, unconstrained by what civ they're supposed to be for.

Hope that helps! So, as an example, I believe this would give Washington of the Americans the city at ix,iy (if there were say 11 living civs):

success = createNewPlayer( 11, 0, 26, city.getX(), city.getY() )

In slot 11, create America with Washington as leader. To instead create America with Sid as its leader (hah!):

success = createNewPlayer( 11, 0, 0, city.getX(), city.getY() )

Glad things are working better for you now!
 
Padmewan said:
After flailing a little more, this might be a workaround?
Code:
if (city.getOwner() == CyGame().getActivePlayer()):
	success = game.createNewPlayer(iSlot, 1, 1, iX, iY )
	if( not success ) :
		pyNewPlayer = PyPlayer(iSlot)
		pyNewPlayer.initCity(iX,iY)
...it's working for me :)

Absolutely! As long as you specify an empty slot, a valid civ type, leader type, and the plot at ix,iy is usable, the slot and civ get properly set up. Then, if the city or settler giving goes awry for some reason, the slot is ready but the civ will be set to dead due to lack of units/cities. But, since they're set up you can totally then give them something, like initCity, initUnit, or acquireCity. Works for reincarnating the same civ that was killed off earlier too (that's how the Python implementation of the BarbarianCiv mod worked).
 
So, what would I have to do, if for example in a game with 4 random nations, in 1000AD I want to add a new random nation with its real/own leader?

Second question: So, what would I have to do, if for example in a game with 4 random nations, one civ splits up to give half of the splitting civ to the new player.
 
Alright, this looks to be one of the most awesome additions I've ever seen to a Civ game.

I had two questions/suggestions, though.

1.) This whole revolution idea is well and good, however... when part of your own nation has a revolution, and becomes a new nation, is it possible to give you the option of becoming the leader of the new nation instead of continuing as the leader of the old? That would be quite wonderful.

For example, in a current game I'm playing, as Frace (in Terra map) I have a huge colonial nation of twelve cities on the far continent. If that nation rebelled, under your mod and with my idea in place, you could become the leader of that far-flung new world nation. And France would still exist. (and probably be pissed.)

2.) Another thing. If you successfully rebel, and manage to stay free, you should add a new negative diplomacy modifier to the original nation, say a -5 or something, due to rebelling. "You rebelled against us! -5" That sort of thing.

3.) Another interesting idea would be a limited way to undo a rebellion. It's similar to the idea of creating a new nation when you take an enemy capital, only its opposite. If you can retake the rebelling region's capital, in, say, 20 (or 15, 10, or whatever) turns, the whole nation reverts back to you, albeit with extra unhappiness and an added chance to rebel again. Is this one possible? (If you decided to become the new nation, and it failed, your leadership reverts to the old nation, perhaps.)

These would be awesome. And with all that you're currently doing already, I would hope it would be possible to implement these things to your mod. At the very least point #1. With that, rebellions would become really fun, and not just damaging to your nation.

Imagine: Can you survive against the combined military/economic/industrial might of your former empire, which you had brought to great power yourself? Can you stand against the armies you built, the infrastructure you designed, all of the power that you yourself had created?

Ahh... now THAT would be the greatest Civ game of all time. Wouldn't it?
 
The new civs, on a terra map at least, easily caught up with the others and indeed, the second civ (after me) was one of the late-comers. And indeed, since the late-comers had that continent to themselves, the second highest ranking civ also happened to be the largest geographically.

They probably would not fair so well on maps where the initial players are distributed more evenly, but either way, they did pretty well for themselves. On the other hand, they also settled into full civs fairly early. Somewhat later on, there'd have been very very little free space for them.
 
RogerBacon said:
I remember trying that months ago and it resulted in the game saying I had lost. Is that function suppose to let you regain control after [integer] number of turns? If so, it didn't work for me.

Roger Bacon
It's meant to. For me it spawned a lion on the ice which kept me alive.

NOTE to avoid confusion: This is a discussion of a Firaxis created debug function, not the code used by the AIAutoPlay functions of this mod.
 
The Great Apple said:
It's meant to. For me it spawned a lion on the ice which kept me alive.

NOTE to avoid confusion: This is a discussion of a Firaxis created debug function, not the code used by the AIAutoPlay functions of this mod.

If you check out the SDK code for that function, it does basically kill you off and then after [int turns] is over, it calls:

Code:
void CvGame::reviveActivePlayer()
{
	if (!(GET_PLAYER(getActivePlayer()).isAlive()))
	{
		setAIAutoPlay(0);

		GC.getInitCore().setSlotStatus(getActivePlayer(), SS_TAKEN);
		GET_PLAYER(getActivePlayer()).initUnit(((UnitTypes)0), 0, 0);
	}
}

Unit Type 0 is a lion, and coordinate 0,0 is the bottom left corner, always ice! Definitely a weird function.
 
Caesium said:
So, what would I have to do, if for example in a game with 4 random nations, in 1000AD I want to add a new random nation with its real/own leader?

This is basically what the Barbarian Civ code does. I'll paste that code in here with some extra comments so you can see what it does:

Code:
for i in range(0,gc.getMAX_CIV_PLAYERS()) :
      if( not gc.getPlayer(i).isEverAlive() ) :
             newPlayerIdx = i
             break
This loops through the player slots from 0 to 17 until it finds one that has never been alive. For your example, slots 0-3 would be full so newPlayerIdx would be set to 4. If you didn't care about overwriting a civ that may have existed but is now dead, you could instead use .isAlive() ...

Code:
            # Can reincarnate as a minor civ if you want
            iMinor = CvUtil.findInfoTypeNum(gc.getCivilizationInfo,gc.getNumCivilizationInfos(),'CIVILIZATION_MINOR')
            # Will cause problems when looking for capital later on, as barbs have no capital ... otherwise works
            iBarbarian = CvUtil.findInfoTypeNum(gc.getCivilizationInfo,gc.getNumCivilizationInfos(),'CIVILIZATION_BARBARIAN')
            availableCivs = list()
            for civType in range(0,gc.getNumCivilizationInfos()) :
                if( not civType == iBarbarian ) :
                    if( not civType == iMinor or self.allowMinor ) :
                        taken = False
                        for i in range(0,gc.getMAX_CIV_PLAYERS()) :
                            if( civType == gc.getPlayer(i).getCivilizationType() ) :
                                taken = True
                                break
                        if( not taken ) :
                            availableCivs.append(civType)

This loops through all the defined civ types and makes a list of ones that are not currently in the game. It also screens out the Barbarian civ and depending on the polarity of self.allowMinor the Minor civ. After this, availableCivs is a list containing all the civs not currently in the game.

Code:
newCivIdx = availableCivs[game.getSorenRandNum(len(availableCivs),'BarbarianCiv: pick unused civ type')]

This picks a random civ from the availableCivs list. A similar procedure is used to pick a leader for the civ:

Code:
            leaderList = list()
            for leaderType in range(0,gc.getNumLeaderHeadInfos()) :
                if( gc.getCivilizationInfo(newCivIdx).[B]isLeaders[/B](leaderType) ) :
                    leaderList.append(leaderType)

            if( len(leaderList) < 1 ) :
            
            newLeaderIdx = leaderList[game.getSorenRandNum(len(leaderList),'BarbarianCiv: pick leader')]

This creates a list of all the leaders for the civ, then picks a random leader from the list. As far as I can tell, there is no info in the leader definition saying which civ they belong to, so you have to use the civ's isLeaders() function. With all this info set up, you can then call the createNewPlayer function:

Code:
success = game.createNewPlayer( newPlayerIdx, newCivIdx, newLeaderIdx, ix, iy )

Where ix and iy are the coordinates of a city you want to give them or the coordinates to spawn a settler for them.

Caesium said:
Second question: So, what would I have to do, if for example in a game with 4 random nations, one civ splits up to give half of the splitting civ to the new player.

Follow the same procedure above, passing the coordinates of the first city you want to give them to the createNewPlayer function. Then loop through the remaining cities using player.acquireCity(...), if you want an example this is done in the Barbarian Civ code as well. Good luck!
 
Top Bottom