Quick Modding Questions Thread

Which is max limit of units, buildings, projects, promotions, civilizations, leaders in CIV4BTS ?
2^15=32k. At least that is the limitation when handling IDs and I'm unaware of any other limitations. However being a 32 bit game, I suspect you would hit the 4 GB memory limit before including such a massive amount of 3D models.

I haven't looked at your CTD yet. I can't justify making it higher priority than my other urgent modding tasks.
 
Is there a way to make a civilization declare war on another civilization through python?
So say I would like Macedon to declare war on Persia on turn lalala, how would I do that?

Also, how could I make a message appear to the human player.
Say around 1800 BC I want a message to appear like "The Sumerian civilization has collapsed into anarchy!" how could I do that?
 
Even without modifying the DLL, it is a good place to look for python exposed functions. They are in Cy*Interface.cpp. Since war is between teams rather than players, the file to look at would be CyTeamInterface.cpp
PHP:
.def("canChangeWarPeace", &CyTeam::canChangeWarPeace, "bool (int /*TeamTypes*/ eTeam)")
.def("canDeclareWar", &CyTeam::canDeclareWar, "bool (int /*TeamTypes*/ eTeam)")
.def("declareWar", &CyTeam::declareWar, "void (int /*TeamTypes*/ eTeam, bool bNewDiplo, int /*WarPlanTypes*/ eWarPlan) - Forces your team to declare War on iTeam")
.def("makePeace", &CyTeam::makePeace, "void (int /*TeamTypes*/ eTeam) - Forces peace between your team and iTeam")
.def("canContact", &CyTeam::canContact, "bool (int /*TeamTypes*/ eTeam)")
.def("meet", &CyTeam::meet, "void (int /*TeamTypes*/ eTeam, bool bNewDiplo) - forces team to meet iTeam")
.def("signOpenBorders", &CyTeam::signOpenBorders, "void (int /*TeamTypes*/ eTeam)")
.def("signDefensivePact", &CyTeam::signDefensivePact, "void (int /*TeamTypes*/ eTeam)")
This would make the call something like
PHP:
gc.getTeam(player.getTeam()).declareWar(enemyPlayer.getTeam(), True, WarPlanTypes.WARPLAN_TOTAL)
The warplans are in CyEnumInterface.cpp. Just search for WarPlanTypes.

I think that should declare the war (I didn't actually test this). Next step is to figure out where in python to write it to get it to activate at the right time.
 
Quick Question: is it possible to have a wonder to grant more than 1 free building type?
For example Stonehenge grants free monuments in all cities. Can add a list of additional free building to this? So it grants 2 different buildings?

Thanks!

I wanted to do something similar but did not find a way that worked.
 
Quick Question: is it possible to have a wonder to grant more than 1 free building type?
For example Stonehenge grants free monuments in all cities. Can add a list of additional free building to this? So it grants 2 different buildings?

Thanks!

With SDK, but you can with XML too.

IDEA:
But you can cheat game, first you have one wonder, and wonder will give you some free building (Stonehenge -> Monument), put additional free building in your free building (example: Monument will give Free Granary in every city).
But what if enemy capture some of your cities and Monument survive, he will get free granary in every city (that is bad, and you don't want that), what to do, just put that monument never survive city capturing.
 
With SDK, but you can with XML too.

IDEA:
But you can cheat game, first you have one wonder, and wonder will give you some free building (Stonehenge -> Monument), put additional free building in your free building (example: Monument will give Free Granary in every city).
But what if enemy capture some of your cities and Monument survive, he will get free granary in every city (that is bad, and you don't want that), what to do, just put that monument never survive city capturing.

Yeah,but this would not work for simple buildings, because I really don't want Monument to grant granaries ;)
 
Without SDK, the python solution will be to add a dummy wonder that provides the other set of free buildings when main wonder built.
 
Even without modifying the DLL, it is a good place to look for python exposed functions. They are in Cy*Interface.cpp. Since war is between teams rather than players, the file to look at would be CyTeamInterface.cpp
PHP:
.def("canChangeWarPeace", &CyTeam::canChangeWarPeace, "bool (int /*TeamTypes*/ eTeam)")
.def("canDeclareWar", &CyTeam::canDeclareWar, "bool (int /*TeamTypes*/ eTeam)")
.def("declareWar", &CyTeam::declareWar, "void (int /*TeamTypes*/ eTeam, bool bNewDiplo, int /*WarPlanTypes*/ eWarPlan) - Forces your team to declare War on iTeam")
.def("makePeace", &CyTeam::makePeace, "void (int /*TeamTypes*/ eTeam) - Forces peace between your team and iTeam")
.def("canContact", &CyTeam::canContact, "bool (int /*TeamTypes*/ eTeam)")
.def("meet", &CyTeam::meet, "void (int /*TeamTypes*/ eTeam, bool bNewDiplo) - forces team to meet iTeam")
.def("signOpenBorders", &CyTeam::signOpenBorders, "void (int /*TeamTypes*/ eTeam)")
.def("signDefensivePact", &CyTeam::signDefensivePact, "void (int /*TeamTypes*/ eTeam)")
This would make the call something like
PHP:
gc.getTeam(player.getTeam()).declareWar(enemyPlayer.getTeam(), True, WarPlanTypes.WARPLAN_TOTAL)
The warplans are in CyEnumInterface.cpp. Just search for WarPlanTypes.

I think that should declare the war (I didn't actually test this). Next step is to figure out where in python to write it to get it to activate at the right time.
Well I don't know anything about python, so unless somebody can give me an exact code I can't do anything.
How is it handled in scenarios like Road to War?
And anybody know the answer to my second question?
 
I have some PYTHON problem, i want to automatic raze city on city capture, if unit have some specific promotion city will be razed on city capture.
I have some realization and this work, i am really get what i want, BUT if I (not AI) do that i get some python errors, if AI do that there is no errors. Sorry for lots of comments inside code. Please see:

Code:
[COLOR="Blue"]class[/COLOR] CvEventManager:
	[COLOR="Blue"]def[/COLOR] __init__(self):
...
## RECONSTRUCTION Start
		self.TargetFound = 0
## RECONSTRUCTION End	
...
...
...
	[COLOR="Blue"]def[/COLOR] onCityAcquired(self, argsList):
		'City Acquired'
		iPreviousOwner,iNewOwner,pCity,bConquest,bTrade = argsList
## RECONSTRUCTION Start
		pPlayerNew = gc.getPlayer(iNewOwner)
		pPlayerPrevious = gc.getPlayer(iPreviousOwner)
		if bConquest:
			#bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())
			#if(bPlayer.getID() == iNewOwner):
			#if(pPlayerNew == bPlayer):
				pPlotX = CyMap().plot(pCity.getX(), pCity.getY())
				#self.TargetFound = 0
				#CyInterface().addMessage(0,true,15,"onCityAcquired: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iNewOwner,true,15,"Osvajac-Broj jedinica porazeni: "+str(CyTranslator().getText(str(pPlayerPrevious.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iNewOwner,true,15,"Osvajac-Broj jedinica osvajac: "+str(CyTranslator().getText(str(pPlayerNew.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iPreviousOwner,true,15,"Porazeni-Broj jedinica porazeni: "+str(CyTranslator().getText(str(pPlayerPrevious.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				#CyInterface().addMessage(iPreviousOwner,true,15,"Porazeni-Broj jedinica osvajac: "+str(CyTranslator().getText(str(pPlayerNew.getNumUnits()),())),'',0,'',13,-1,-1, true,true)
				(loopUnit, iter) = pPlayerNew.firstUnit(false)
				while(loopUnit):
					if(loopUnit.isHasPromotion(gc.getInfoTypeForString("PROMOTION_CITY_RAZE"))):
						if(loopUnit.getX() == pCity.getX() and loopUnit.getY() == pCity.getY()):
							for iPopulation in xrange(pCity.getPopulation()):
								pNewUnit = pPlayerNew.initUnit(loopUnit.getUnitType(), loopUnit.getX(), loopUnit.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
								pNewUnit.finishMoves()
								self.TargetFound = 1
							#pPlayerNew.disband(pCity)
							break
					(loopUnit, iter) = pPlayerNew.nextUnit(iter, false)
				#if(self.TargetFound == 1):
				#	pCity.kill()
#for iUnit in xrange(pPlotX.getNumUnits()):
#	pUnitX = pPlotX.getUnit(iUnit)
#	if(pUnitX.getOwner() == iNewOwner and pUnitX.isHasPromotion(gc.getInfoTypeForString("PROMOTION_CITY_RAZE"))):
#		for iPopulation in xrange(pCity.getPopulation()):
#			pNewUnit = pPlayerNew.initUnit(pUnitX.getUnitType(), pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
#		pPlayerNew.disband(pCity)
#		break
## RECONSTRUCTION End
		CvUtil.pyPrint('City Acquired Event: %s' %(pCity.getName()))
	
	[COLOR="Blue"]def[/COLOR] onCityAcquiredAndKept(self, argsList):
		'City Acquired and Kept'
		iOwner,pCity = argsList
## RECONSTRUCTION Start
		#if(self.TargetFound == 1):
		#CyInterface().addMessage(0,true,15,"onCityAcquiredAndKept: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
		#CyInterface().addMessage(iOwner,true,15,"Grad je dodeljen i zadrzan: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
		#self.TargetFound = 0
		#pCity.kill()
## RECONSTRUCTION End
		CvUtil.pyPrint('City Acquired and Kept Event: %s' %(pCity.getName()))
## RECONSTRUCTION Start
		if(self.TargetFound == 1):
			#CyInterface().addMessage(0,true,15,"onCityAcquiredAndKept(IF): "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
			self.TargetFound = 0
			[COLOR="Red"]pCity.kill()[/COLOR]
## RECONSTRUCTION End
	
	[COLOR="Blue"]def[/COLOR] onCityLost(self, argsList):
		'City Lost'
		city = argsList[0]
		player = PyPlayer(city.getOwner())
## RECONSTRUCTION Start
		#if(self.TargetFound == 1):
		self.TargetFound = 0
		#CyInterface().addMessage(0,true,15,"onCityLost: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
		#CyInterface().addMessage(city.getOwner(),true,15,"Grad je pao: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
		#CyInterface().addMessage(player.getID(),true,15,"2-Grad je pao: "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
		#self.TargetFound = 0
		#pCity.kill()
## RECONSTRUCTION End
		
		if city.getID() == self.iArcologyCityID:
			city.plot().setImprovementType(gc.getInfoTypeForString("IMPROVEMENT_CITY_RUINS_ARCOLOGY"))
		
		if (not self.__LOG_CITYLOST):
			return
		CvUtil.pyPrint('City %s was lost by Player %d Civilization %s' 
			%(city.getName(), player.getID(), player.getCivilizationName()))

if i capture city and agree to kept that city (of course the city is razed, because my code do that i that is what i want, but...), i get this error:

Spoiler :
CqYI7Ul.jpg


Spoiler :
mMseTlp.jpg


My additional idea.
Maybe to call onCityRazed from onCityAcquiredAndKept, but if is this good idea, how to do that ?

I hope that platyping will see this.
 
It would appear that you have an indent problem. Python is quite picky about this and I'm not sure if too many tabs will cause problems. Too few will.

if i capture city and agree to kept that city (of course the city is razed, because my code do that i that is what i want, but...)
Wouldn't it be better to place your code before the question rather than after? It's not a major issue, but a window with two raze buttons seems pointless.
 
As night said, indentation is the main issue and I would not separate into two portions either.
If you want to comment an if statement temporarily, I suggest you replace it with
Code:
if True:

to avoid indentation problems.
 
Perhaps, but the problem comes from Civ4lerts, no?
 
@Nightinggale, @platyping, @isenchine

I forgot to say that is this part of code is mod component for my Alien Invasion (which is part of my RECONSTRUCTION mod), they can spawn everywhere on the map and start destroying everything on map :D

I just not realize what will do if they spawn on plot which have city, but i have idea, city will be instant razed.

It would appear that you have an indent problem. Python is quite picky about this and I'm not sure if too many tabs will cause problems. Too few will.


Wouldn't it be better to place your code before the question rather than after? It's not a major issue, but a window with two raze buttons seems pointless.

Yes, yes, i try that but i really don't have any idea how to do that :confused:
I don't know in which function to write code.

If you capture enemy city you get two decisions Kept City or Raze it. If your unit which is captured enemy city have PROMOTION_CITY_RAZE enemy city will be razed whatever you chose.

If you chose to kept the city (previous is your unit with PROMOTION_CITY_RAZE captured that city), city will be razed, but there is no calling onCityRazed and you don't get message Player %d Civilization %s City %s was razed by Player %d
, there is for all players (AIs and players). But if i capture and chose to kept city is razed and i get several tabs with errors. If is necessary i will post every error which i get.

As night said, indentation is the main issue and I would not separate into two portions either.
If you want to comment an if statement temporarily, I suggest you replace it with
Code:
if True:

to avoid indentation problems.

Same answer as for Nightinggale.
Sorry platy but i don't understand your statement about if True: i don't know python excellent as you.

Perhaps, but the problem comes from Civ4lerts, no?

These several tabs are chain reaction which is caused by this part of code:
Code:
	[COLOR="Blue"]def[/COLOR] onCityAcquiredAndKept(self, argsList):
	....
		if(self.TargetFound == 1):
			#CyInterface().addMessage(0,true,15,"onCityAcquiredAndKept(IF): "+str(CyTranslator().getText(str(self.TargetFound),())),'',0,'',13,-1,-1, true,true)
			self.TargetFound = 0
			[COLOR="Red"][B]pCity.kill()[/B][/COLOR]

pCity.kill() is cause all of these tabs.
 
Since the errors are from Civ4lerts, chances are Civ4lerts is trying to display some messages etc, which obviously is only meant for humans which is why errors don't trigger when AI do the same stuff.

Most likely it is trying to display messages about the city, which no longer exists.
 
Is your city killed or not?

Why don't you kill the city immediately at onCityAcquired (instead of self.TargetFound = 1) and forget the other places?

Still you might have a problem with Civ4lerts as this is not the usual way of handling a conquered city (I don't have that mod comp).

Edit: was writing this before seeing Platy's post.
 
@for ALL
Do you have some idea for this error for human players or i will accept this error as some normal activity?
As i already said this error is only for human players and just show several error tabs without any CTD or game closing or game destabilization.

Since the errors are from Civ4lerts, chances are Civ4lerts is trying to display some messages etc, which obviously is only meant for humans which is why errors don't trigger when AI do the same stuff.

Most likely it is trying to display messages about the city, which no longer exists.

Exactly that platy, for example, you send me a letter, and i burn your letter, and after that i want to read your letter which no more exist, that is impossible.

Is your city killed or not?

Why don't you kill the city immediately at onCityAcquired (instead of self.TargetFound = 1) and forget the other places?

Still you might have a problem with Civ4lerts as this is not the usual way of handling a conquered city (I don't have that mod comp).

Edit: was writing this before seeing Platy's post.

Yes, my city is killed in onCityAcquiredAndKept.

I try that and if i kill city in onCityAcquired i get CRASH TO DESKTOP.
 
Do you have some idea for this error for human players or i will accept this error as some normal activity?
As i already said this error is only for human players and just show several error tabs without any CTD or game closing or game destabilization.

What is Civ4lerts, the old version or Platy's?

The last Python error is the most important one. Note the line that is referred there and try to adjust it if possible.
 
Back
Top Bottom