1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

RFC Modding Central

Discussion in 'Rhye's and Fall Modmods' started by Linkman226, Aug 29, 2011.

  1. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    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?
     
  2. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  3. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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)
     
  4. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    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.
     
  5. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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"?
     
  6. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    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]
     
  7. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  8. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    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.
     
  9. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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]],
     
  10. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    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.
     
  11. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  12. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    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.
     
  13. embryodead

    embryodead Caliph

    Joined:
    Jan 1, 2003
    Messages:
    5,179
    Location:
    basement
    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!
     
  14. Leoreth

    Leoreth 古典部の会員 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    32,454
    Gender:
    Male
    Location:
    Kamiyama
    Oh, that's good to know.
     
  15. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  16. GnomeChomsky

    GnomeChomsky Chieftain

    Joined:
    Jun 21, 2012
    Messages:
    22
    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.
     
  17. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  18. Linkman226

    Linkman226 #anarchy

    Joined:
    Sep 14, 2007
    Messages:
    2,493
    I assume you figured it out?

     
  19. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    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.
     
  20. srpt

    srpt Deist

    Joined:
    May 10, 2010
    Messages:
    2,025
    Location:
    Toronto
    I'd like "def onCombatResult" in CvEventManager, which has two arguements, pWinner and pLoser, to also distinguish attacker and defender. is this possible?
     

Share This Page