how to get a pointer to a civic type in python?

stmartin

aka. poyuzhe
Joined
Aug 4, 2007
Messages
640
Location
Shanghai
Now may be I'm asking the wrong question, if I'm please pull my ear and teach me:

In CvPlayer.cpp there is a function canRevolution that is exposed to python. I'm using this function to create a little random event. The function declaration looks like this:

Code:
bool canRevolution(CivicTypes* paeNewCivics) const;

Notice its argument is a pointer type instead a plain int like CivicTypes.

I tried to use call this function in Python using the argument gc.getInfoTypeForString("CIVICxxxxxx") but it gives a runtime error, Yes it should be.

Anyone knows how to call this function with a pointer to civic argument in python?
 
canRevolution() expects a list of civic IDs -- not a single civic ID. Instead, use canDoCivics(eCivic) if you want to check if the player can switch the single civic.

If you actually want to change multiple civics at once, you can try using canRevolution() with a Python list or tuple with 5 elements and see if boost does the conversion correctly.
 
In C++ you pass in a pointer for a couple reasons:

  • You want the function to modify the value the pointer points to (seems unlikely in this case).
  • You want to pass in an array of values, so you pass a pointer to the first one.
But the best way to find out is to read the code:

Code:
bool CvPlayer::canRevolution(CivicTypes* paeNewCivics) const
{
	...
	for (iI = 0; iI < GC.getNumCivicOptionInfos(); ++iI)
	{
		...
		if (getCivics((CivicOptionTypes)iI) != [B]paeNewCivics[iI][/B])
		{
			return true;
		}
	}
}

Here you can see that canRevolution() is treating paeNewCivics as an array and checking that at least one of the civcs passed in is not in use at the moment.
 
Very cool, I feel a bit more enlightened now, thanks a lot:)

But...not enlightened enough, I'm afraid...

Now I have checked if player can change to specific civic, how can I make it actually change it? I know there's a function called revolution(), but that one also expects an array... This time, there seems to be no handy functions jumping out like canDoCivic() did.

May be I just have to use revolution(), and pass it with a list?
 
Take a look at CvCivicsScreen.py. In there you can see that it uses a list for canRevolution() and revolution(), so boost (Python to C++ layer) must be doing the conversion. This screen should contain all the necessary sample code for your needs.
 
Some progress report and a little discovery:):

1. I tried passing a list like [4,5,10,15,20] to canRevolution and Revolution, did debug work with in-game python console, the console keeps giving error message like "doesn't match C++ signature"

2. I did some searching in this sub-forum and came across some interesting discussion. I used functions like setCivic() and changeAnarchyTurns() to achieve the similar effect of revolution(). It worked!

3. Now something I've discovered. In Cyplayer there is also another function that expects the similar argument:
Code:
int getCivicAnarchyLength(boost::python::list& /*CivicTypes**/ paeNewCivics);
I compared it with canRevolution() and saw the difference:
Code:
bool canRevolution(int /*CivicTypes**/ paeNewCivics);
The difference is
Code:
boost::python::list&
. I guess this is what you've said that make a list argument work.

4. I tried to run the getCivicAnarchyLength function with In-game python console, passing it a list like [4,5,10,15,20], and it accepts it, and it works!

5. Now I speculates: if we change the code in CyPlayer that defines the canRevolution and revolution function, making it similar as getCivicAnarchyLength, and recompile the dll, we may actually be able to use these functions by passing it a list argument in Python!

Is that cool? Or is that wrong? :lol:
 
That all sounds correct, and I was surprised to see that canRevolution() lacked the "boost::python::list&", but upon closer examination of the Civics screen, I see what I missed.

I saw the name of the list that holds the civics and that it passed it to the getCivicAnarchyLength() function and assumed it would work for canRevolution(). However, here's how it actually does the revolution when you click the REVOLUTION button.

Code:
# Revolution!!!
def Revolution(self, inputClass):

	activePlayer = gc.getPlayer(self.iActivePlayer)

	if (inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED) :
1		if (activePlayer.canRevolution(0)):
			messageControl = CyMessageControl()
2			messageControl.sendUpdateCivics(self.m_paeDisplayCivics)			
		screen = self.getScreen()
		screen.hideScreen()

Line 1 checks if you can have a revolution. By passing in 0 (a NULL array in C++), it's merely checking that you aren't within the 5 turn waiting period after recently revolting.

Line 2 actually broadcasts the civics change message, and I have to assume that the first part of sendUpdateCivics() actually changes the civics. You might want to try this code (copy it where you need it) before mucking about in the DLL.
 
I tried CyMessageControl().sendUpdateCivics(list) and it works fine for the current player I am controlling. However, when trying to trigger the event for some other player, the event triggered fine, but when the other player is supposed to revolution, it turns out to be me that sinks into anarchy and changes civic. I haven't figured out a way to use this function to trigger revolution for other players. Any suggestions?
 
Bummer, I hadn't considered that. The function doesn't take a player ID, so I don't see how you can use it for other players. :(

If you are going to be making DLL changes anyway, that's the way to go.
 
Well, actually, I guess this function can be really useful:)

Because in 'Real' game, you will never do things like I just did, that is, try to trigger some event for another player. In real game, it's your turn, then the AI's turn. In AI's turn, if the particular event triggers, the current player will be the AI player, and the one who is affected by the sendUpdateCivics() function will be the AI player.

So actually it seems I don't need to mess with SDK...for the time being:)
 
In AI's turn, if the particular event triggers, the current player will be the AI player, and the one who is affected by the sendUpdateCivics() function will be the AI player.

Careful! I can't see the code for CyMessageControl so I can't say definitively, but it probably doesn't work as you think. I suspect it operates on the active player, and this is always the person sitting at the computer -- not the player whose taking their turn.

  • In single player games, it's always the human player.
  • In PBEM, it's the human on whose computer the game is running at any given moment.
  • In hotseat, it's the human who is taking their turn.
  • In multiplayer, it's the ID of the human player on each human's computer.
Thus, it will never be an AI.

Now, it's possible that this function operates on the player whose turn it is, but that would deviate from most other functions that don't take a player ID, specifically the multiplayer message broadcasting functions in CyMessageControl I think.

It wouldn't be hard to set up a test. Put your code into a BeginPlayerTurn event that forces a revolution if the current player isn't the active player. If the AIs revolt, you're set.
 
You are right, this function does not work the way I wanted it to.

It's always me that revolt.:lol:

Thanks for pointing this out.:)
 
Top Bottom