RFC Modding Central

I'm pretty sure the AI disbands them, yes. SoI has some way to designate certain independent cities as more strongly defended (like Chittor), did you try to use that instead?
 
sometimes its the odd choice that solves the problem: changed the city owner from Independent4 to Independent3 and the units stay. I guess Independent4 had too many units on the map or something. anyway the Bactrian conquest of Taxila should be less of a walk-over now.
 
I'm making a python method that fixes incongruous city conquests by faraway civs.

if an AI civ captures a city that is not in any of its region sets (core, normal or broader) it will give the city to a local civ (or indy cities) and its army is teleported (ie deleted and recreated) back to the capital. they will also get some gold and a little stability boost. the city flipping and army teleporting is working but I can't seem to do anything to the unit that actually takes the city. python print statements tell me the unit is not there at all.

any ideas? here's the method so far:

Spoiler :
Code:
def onCityAcquiredAndKept(self, argsList):
		iPreviousOwner, iNewOwner, city, bConquest, bTrade = argsList		

		pNewOwner = gc.getPlayer(iNewOwner)
		
		if bConquest and not city.plot().getRegionID() in con.lCoreRegions[iNewOwner] and not city.plot().getRegionID() in con.lNormalRegions[iNewOwner] and not city.plot().getRegionID() in con.lBroaderRegions[iNewOwner]:
			iLocalPower = -1
			for iLoopCiv in range(con.iNumPlayers):
				if gc.getPlayer(iLoopCiv).isAlive() and city.plot().getRegionID() in con.lCoreRegions[iLoopCiv] or city.plot().getRegionID() in con.lNormalRegions[iLoopCiv]:
					iLocalPower = iLoopCiv
					break
			
			if iLocalPower != -1:
				for x in range(city.getX() -2, city.getX() + 2):
					for y in range(city.getY() - 2, city.getY() + 2):
						plot = gc.getMap().plot(x, y)
						iNumUnits = plot.getNumUnits()
						j = 0
						for i in range(iNumUnits):
							unit = plot.getUnit(j)
							unitType = unit.getUnitType()
							if (unit.getOwner() == iNewOwner):
								unit.kill(False, iNewOwner)
								if pNewOwner.getCapitalCity().getX() != -1 and pNewOwner.getCapitalCity().getY() != -1:
									utils.makeUnit(unitType, iNewOwner, [pNewOwner.getCapitalCity().getX(), pNewOwner.getCapitalCity().getY()], 1)
								else:
									randomCity = utils.getRandomCity(iNewOwner)
									utils.makeUnit(unitType, iNewOwner, [randomCity.getX(), randomCity.getY()], 1)
										
							else:
								j += 1
				utils.flipCity((city.getX(), city.getY()), 0, 0, iLocalPower, [])
				utils.makeUnit(con.iSpearman, iLocalPower, [city.getX(), city.getY()], 2)
 
Isn't it a little unfair to just take the first civ that happens to have its normal area there, even if it could be a later civ's core?

Code:
lCoreList = []
lNormalList = []
lBroaderList = []

for iLoopCiv in range(con.iNumPlayers):
        if gc.getPlayer(iLoopCiv).isAlive():
                if city.plot().getRegionID() in con.lCoreAreas[iLoopCiv]:
                        lCoreList.append(iLoopCiv)
                elif city.plot().getRegionID() in con.lNormalAreas[iLoopCiv]:
                        lNormalList.append(iLoopCiv)
                elif city.plot().getRegionID() in con.lBroaderAreas[iLoopCiv]:
                        lBroaderList.append(iLoopCiv)

if len(lCoreList) > 0: lCivList = lCoreList
elif len(lNormalList) > 0: lCivList = lNormalList
else: lCivList = lBroaderList

if len(lCivList) > 0:
        iRand = gc.getGame().getSorenRandNum(len(lCivList), 'random civ')
        iLocalCiv = lCivList[iRand]
This way civs that have a core will be preferred over those with normal or broader areas, and a random civ will be chosen.
 
yeah that would be better. but what about that unit? is it in limbo while this is being called? do I have to get rid of it on the next turn?

another thing:

I wanted to make a victory condition that requires the Judeans to have open borders with all civs that have Judaism in one of their cities. in order to avoid having to check the condition more often than necessary I wanted to make it check each time an open borders agreement is made, but I can't find a check like that. can I make one? is that what is referred to as "exposing to python"?
 
What unit exactly?

For your other question, "exposing to Python" is usually used to refer to the process of making a DLL method available to a Python class that represents it, for example when edead added provinces, he first created the CvPlot::getRegionID() method in the DLL and the exposed it to Python so you can call PyPlot.getRegionID().

What you need is a new event trigger which reports the "onOpenBorders" event every time an open borders agreement is signed (this can then trigger a Python method).

First you have to declare this new trigger as a method in CvEventManager.cpp, call it for example CvEventReporter::openBorders(TeamTypes eTeam, TeamTypes eTargetTeam, bool bNewValue). This method will call a similar method you'll have to define in CvDLLPythonEvents.cpp, which is conventionally called CvDLLPythonEvents::reportOpenBorders(). All you do there is to put your parameters into appropriate Python wrapper classes or convert them to Python compatible data types (like TeamTypes -> int) and put them into a CyArgsList object and send everything to Python with postEvent(argsList).

Then you only have to locate the part of the code where open borders are actually signed (this would be CvTeam::setOpenBorders()) and call
Code:
CvEventReporter::getInstance().openBorders(getID(), eTeam, bNewValue);
Now you've created a new event in the DLL, but still have to tell Python to "listen" to it. To do this, add it to EventHandlersMap in CvEventManager.py (it should be easy to follow the pattern) and in the __init__ method of CvRFCEventHandler.py, you add an event handler to the event manager (again, it's an easy pattern). Now you just have to define your new "onOpenBorders" method in CvRFCEventHandler.py :)

[That sounds quite complicated, but most of the time you just have to emulate what's already there]
 
the unit I'm talking about is the unit that captures the city. for some reason it doesn't get deleted and recreated along with the others. the method runs through all the plots within 1 plot of the city and deletes and recreates elsewhere any units found there belonging to the the civ that took the city. this works for all units, including a spy I preplaced on the city plot itself, but not for the unit that took the city, it stays there. I've tried flipping the city first and then dealing with the units and also units first and then city, but either way, that 1 unit is unaffected. also if I ask python to report the number of units in each plot, that unit is not counted.

thanks so much for the info on the other question. I can't wait to try it out. it will be the most involved thing I have done with the DLL so far.
 
the unit I'm talking about is the unit that captures the city. for some reason it doesn't get deleted and recreated along with the others. the method runs through all the plots within 1 plot of the city and deletes and recreates elsewhere any units found there belonging to the the civ that took the city. this works for all units, including a spy I preplaced on the city plot itself, but not for the unit that took the city, it stays there. I've tried flipping the city first and then dealing with the units and also units first and then city, but either way, that 1 unit is unaffected. also if I ask python to report the number of units in each plot, that unit is not counted.
Your code looks correct (although you're currently not iterating a square around the city, remember that range(x, y) iterates [x, x+1, ...., y-2, y-1]) so maybe you're right that the unit that conquers the city is "in limbo". No idea how to deal with it.
 
I'm still trying to get this to work. (the above method of overturning distant AI city conquests)

now I am trying to make the city flip and sending units home occur on the next turn, so I am trying to use a list (or actually a tuple?) in the StoredData module copied from the Victory goals.

I made a "lDistantConquest" and the "set' and "get" methods in the sd module, copied exactly from the "lGoals" and its methods.

the 3 values are intended to be a boolean and city coords.

in "onCityAcquired" I have "sd.setDistantConquest(iNewOwner, 0, 1)" just like the "sd.setGoal(iCiv, 0, 1)" in Victory.py. for now I am just trying to set the boolean, but I get this exception:

TypeError: object does not support item assignment

here are the bits of code:

Spoiler :
Code:
	def onCityAcquiredAndKept(self, argsList):
		iPreviousOwner, iNewOwner, city, bConquest, bTrade = argsList
		
		if bConquest and iNewOwner != utils.getHumanID() and iNewOwner < iNumPlayers and iPreviousOwner >= iNumPlayers and not city.plot().getRegionID() in con.lCoreRegions[iNewOwner] and not city.plot().getRegionID() in con.lNormalRegions[iNewOwner] and not city.plot().getRegionID() in con.lBroaderRegions[iNewOwner]:
			
			sd.setDistantConquest(iNewOwner, 0, 1)

Code:
	# from RFCCWAIWars.py
	
	def getDistantConquest( self, i, j ):
		return self.scriptDict['lDistantConquest'][i][j]

	def setDistantConquest( self, i, j, iNewValue ):
		self.scriptDict['lDistantConquest'][i][j] = iNewValue


Code:
				#------------Distant Conquest
				'lDistantConquest': [[-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1],
					   [-1, -1, -1]],
 
Huh, I thought I posted here. Seems the board ate my post.

Anyway, from my perspective you've made no mistake. The error message suggests that self.scriptDict['lDistantConquest'][iNewOwner][0] does not refer to an integer for whatever reason.
 
would it be at all possible to be able to change game speeds during a game? this way you could run the autoplay of a late-spawning civ on normal speed and then play from there on a slower speed.
 
Theoretically, yes. However it would require a ton of work. I think the easiest way would be to change the calendar's pacing in the XML. And then you would have to adjust a bunch of stuff in the python and the DLL. However this is more of a cheap hack because each time you played a different civ you'd have to readjust the calendar based on their spawn date.
 
I am spawning units in an independent city on the birth of a neighboring civ, to make the city harder to capture. the units appear, but then disappear on the next turn. whats happening? is the AI disbanding them for some reason? this happens after the new civ declares war by entering the independents territory.

It's a bug in Better BTS AI. Thanks to Power of Beer it's fixed here: http://forums.civfanatics.com/showpost.php?p=11572538&postcount=73

Anyone using BBAI (or SoI/RFCM, since that includes BBAI) may want to apply that bugfix to prevent the AI from disbanding units under silly circumstances!
 
Oh, that's good to know.
 
yes thank you to you and Power_of_Beer for finding and fixing that. funny how bugs like that can go undetected for so long.

another question:

in my mod when you are running Slavery and raze a city you get a number of slaves. this happens in python and is working properly. I also would like the popup when you capture the city to say "Raze the city and enslave its people" rather than just "Raze the city" when you are running slavery. I have found the place to do this but I don't how to ask the civic question. here is the code:

Spoiler :
Code:
	if (bRaze)
	{
		gDLL->getInterfaceIFace()->popupAddGenericButton(pPopup, gDLL->getText("TXT_KEY_POPUP_RAZE_CAPTURED_CITY").c_str(), NULL, 1, WIDGET_GENERAL);
	}

so I guess I need something like this:

Spoiler :
Code:
	if (bRaze)
	{
		if civic = slavery
		{
			gDLL->getInterfaceIFace()->popupAddGenericButton(pPopup, gDLL->getText("TXT_KEY_POPUP_RAZE_AND_ENSLAVE_CAPTURED_CITY").c_str(), NULL, 1, WIDGET_GENERAL);
		}
		else:
		{
			gDLL->getInterfaceIFace()->popupAddGenericButton(pPopup, gDLL->getText("TXT_KEY_POPUP_RAZE_CAPTURED_CITY").c_str(), NULL, 1, WIDGET_GENERAL);
		}
	}

but I don't know the syntax required. I've tried to find an example I can copy elsewhere in the code, but no luck so far.
 
pPlayer.getCivic() == iSlavery should work

where pPlayer is a CyPlayer object (I'm assuming of the human player) and you've defined iSlavery somewhere to the integer value of the slavery civic.

pPlayer can be substituted with:

gc.getPlayer(gc.getActivePlayer())

if we're only talking about the human here. But that's assumed, since only the human can respond to pop-ups.
 
yeah I guess I should have said what file I was in, sorry about that. its CvDLLButtonPopup.cpp so its C++ not python.

never mind I got it. sometimes C++ is simpler than I think it will be.
 
I assume you figured it out?

happy to announce that the popup asking whether you want to keep or raze a city on capture now tells you that you can enslave the city if you are running slavery.
 
yeah its funny I had put off that change for ages because it was in the DLL. the effect was all python and worked fine but I wanted to have that text in the popup to make it look more like part of the game and less like an add-on. I get intimidated by C++ because there's a lot of stuff there that is a total blank for me. I honestly didn't think it would be as simple as adding the one line. I thought it would require introducing the whole civics thing into a structure where it wasn't normally. anyway I'm happy its in the mod.
 
I'd like "def onCombatResult" in CvEventManager, which has two arguements, pWinner and pLoser, to also distinguish attacker and defender. is this possible?
 
Top Bottom