Bug Thread

If the attachment thing isn't fixed real soon, I'll just post the code directly - it isn't that much. Actually, it's sort of a good thing it didn't work since after I tried to attach the code I discovered that there was a bug in it: it worked fine with a saved game but failed when starting a new one. It didn't take into account the way that star systems are generated for each location including setting a default build planet during the system generation and it was trying to copy production values to and from non-existent cities at that time and trying with a non-existent planet too (since the build planet variable is initialized to -1 it tried to copy the production data from the non-existent city to the non-existent planet in the non-existent ring -1; that was a lot of non-existence). I have now fixed that and played a new game for a bit over 200 turns without difficulty (using a FFPBUG version with this change).

Before posting it, I'll probably also add the clearing of the stored production on system capture and razing to avoid the possibility of inheriting production (which can't happen in regular Civ as far as I know as I'm pretty sure the city's stored values are cleared when it is captured and there is nothing saved when a city is razed, of course). It'll be pretty easy to do since both functions already loop over all of the building types for each planet to check for removing some of them for the capture and to wipe them all out for the razing, so it is just adding the zeroing of the stored production amounts in the existing building loops in those two places.
 
OK, the attachment posting isn't fixed but my fix is done.

See my previous couple of posts in this thread for what this fixes. The short version is that with this fix the game will now remember how much production you have put into a building on a planet if you switch to producing buildings on a different planet for a while. In one specific case it used to successfully do this (when a building that had production stored for it was already the first thing in the build queue when you switched back to the planet it would recall how much it had already put into it, but only for that one specific case), but now it should always work.

The fix modifies two files. I'm assuming the regular FFP files, not the renamed ones I used in the FFPBUG beta.

1) CvFinalFrontierEvents.py, changes in 4 locations.

1.1) In the onModNetMessage function the handling of the message type defined as self.iNetMessage_AssignBuilding needs to be changed. It is now actually a bit simpler since the production data swap that happens when changing the build palnet is handeled by the function for the star system that does the planet change.

So what used to start with this
Code:
		# Remove a certain amount of population from a planet
		elif (iMessage == self.iNetMessage_AssignBuilding):
		
			#CyMessageControl().sendModNetMessage(FinalFrontier.iNetMessage_AssignBuilding, pSystem.getX(), pSystem.getY(), iPlanetRing, -1)
is different. And yes, the comment before the elif is wrong so I change that too.

Everything in that elif block, which is everything to the end of the function, gets replaced with this:
Code:
		# Change the currently designated build planet
		elif (iMessage == self.iNetMessage_AssignBuilding):
		
			#CyMessageControl().sendModNetMessage(FinalFrontier.iNetMessage_AssignBuilding, pSystem.getX(), pSystem.getY(), iPlanetRing, -1)
			
			iX = iData2
			iY = iData3
			iPlanetRing = iData4
			iRemove = iData5
			
			pPlot = CyMap().plot(iX, iY)
			pCity = -1
			if (pPlot.isCity()):
				pCity = pPlot.getPlotCity()
				
			pSystem = self.getSystemAt(iX, iY)
			pPlanet = pSystem.getPlanet(iPlanetRing)
			
			pOldPlanet = pSystem.getPlanet(pSystem.getBuildingPlanetRing())

			printd("Old Planet: %s (ring=%d,type=%s)" %(pOldPlanet.getName(), pOldPlanet.getOrbitRing(), aszPlanetTypeNames[pOldPlanet.getPlanetType()]))
			printd("New Planet: %s (ring=%d,type=%s)" % (pPlanet.getName(), pPlanet.getOrbitRing(), aszPlanetTypeNames[pPlanet.getPlanetType()]))
			
			# Planet Production Memory Improvement - GE, March-2011
			# If we switched build planet and the first entry in the current build
			# queue was a building that already existed on the planet it removed that
			# entry from the queue but did not check the next entry to see if that
			# building also already existed. Now loop back and check again if we
			# remove something from the queue. Presumably this issue is dealt with
			# in the DLL at some point, but as long as it was being done here it
			# may as well keep checking and remove more than just the first if
			# there are multiple buildings in the queue that already exist on
			# the new planet
			#
			# The main fix is in the pSystem.setBuildingPlanetRing() function.
			# Doing it there also takes care of the AI's planet switching too.
			#
			# There is another piece of code down in the onBuildingBuilt to
			# zero out the stored production for a building that is finished.
			# Likewise there is an additional line of code in onCityAcquired and
			# another in onCityRazed. Each of these zeros out the stored production.
			# No inheriting production from somebody else.
			#
			# There is still probably an issue with production decay (normally,
			# if you don't work on something for a while the saved production
			# starts going down - it is something like -1 hammer per turn if you
			# don't work on it for 10 turns, but this may depend on game speed).

			# Working on a building?
			if (pCity.isProductionBuilding()):
			
				iBuilding = pCity.getProductionBuilding()
			
				bLoop = True
				while bLoop:
					bLoop = False
					if (pPlanet.isHasBuilding(iBuilding)):
						# Planet already has this building, pop the queue
						pCity.popOrder(0, false, true)
						printd("  new planet already has building %d, removing from build queue" %(iBuilding))
						# Check if new production is a building we already have too
						if (pCity.isProductionBuilding()):
							bLoop = True
							iBuilding = pCity.getProductionBuilding()
			
			CyInterface().setDirty(InterfaceDirtyBits.CityScreen_DIRTY_BIT, True)
			
			pSystem.setBuildingPlanetRing(iPlanetRing) # PPMI: this fucntion now does a lot more than it used to.
			
			CyInterface().setDirty(InterfaceDirtyBits.CitizenButtons_DIRTY_BIT, True)
			CyInterface().setDirty(InterfaceDirtyBits.SelectionButtons_DIRTY_BIT, True)

1.2) In the onBuildingBuilt function, zero out any stored production for the building we just produced on the planet where it was produced. Possibly not needed, but done "just in case".

At the end of the function add these lines:
Code:
		# Planet Production Memory Improvement - GE, March-2011
		# This is part 2 of the fix, the first part is in the onModNetMessage function.
		# Here we just zero out the saved production for the building type we just built.
		pPlanet.setBuildingProduction(iBuildingType, 0)
		printd("Zeroed production for building %d on planet %s" %(iBuildingType, pPlanet.getName()))

1.3) In the onCityAcquired function, zero out all the stored production data.

At the beginning of the loop that starts like this
Code:
			# Loop through all buildings
			for iBuildingLoop in range(gc.getNumBuildingInfos()):
				# Has this building
				if (pPlanet.isHasBuilding(iBuildingLoop)):
insert some code to make it look like this
Code:
			# Loop through all buildings
			for iBuildingLoop in range(gc.getNumBuildingInfos()):
				[B]# Planet Production Memory Improvement - GE, March-2011; wipe out all stored production 
				pPlanet.setBuildingProduction(iBuilding, 0)[/B]
				
				# Has this building
				if (pPlanet.isHasBuilding(iBuildingLoop)):

1.4) In the onCityRazed function also zero out the planets' stored production data

Append to this code
Code:
		# Loop through all the planets in the system
		for iPlanetLoop in range(pSystem.getNumPlanets()):
			pPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
			# Loop through all building types
			for iBuildingLoop in range(gc.getNumBuildingInfos()):
				# Set the planet to not have one of these
				pPlanet.setHasBuilding(iBuildingLoop, false)

So that it now looks like this
Code:
		# Loop through all the planets in the system
		for iPlanetLoop in range(pSystem.getNumPlanets()):
			pPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
			# Loop through all building types
			for iBuildingLoop in range(gc.getNumBuildingInfos()):
				# Set the planet to not have one of these
				pPlanet.setHasBuilding(iBuildingLoop, false)
				[B]# Planet Production Memory Improvement - GE, March-2011; wipe out all stored production 
				pPlanet.setBuildingProduction(iBuilding, 0)
[/B]

2) CvSolarSystem.py, changes to the setBuildingPlanetRing method of the CvSolarSystem class

That function now does the save and restore operations between the planet's local Python data and the city object's stored building production values when the current build planet is changed.

Just completely replace the setBuildingPlanetRing function with this:
Code:
	def setBuildingPlanetRing(self, iID):
		# Planet Production Memory Improvement - GE, March-2011
		# This does a lot more work now.
		# 1) Before changing build planet, save the production spent on each building
		#    type from the city's data to the pre-change planet's data
		# 2) After changing build planet, load the new planet's saved building production
		#    values into the city's building production list
		
		iOldBuildingPlanetRing = self.iBuildingPlanetRing
		printd("setBuildingPlanet to %d from %d" %(iID, iOldBuildingPlanetRing))

		self.iBuildingPlanetRing = iID		
		
		pCity = self.getCity()
		if (pCity == -1) or  (iOldBuildingPlanetRing == -1):
			# we are doing map setup so none of the following stuff is relevant
			return

		iNumBuildingTypes = gc.getNumBuildingInfos()
		pPlanet = self.getPlanet(iOldBuildingPlanetRing) # pre-change planet
		for iBuilding in range(iNumBuildingTypes):
			pPlanet.setBuildingProduction(iBuilding, pCity.getBuildingProduction(iBuilding))
			printd("  saved production for building: type = %d, production = %d" %(iBuilding, pCity.getBuildingProduction(iBuilding)))
		
		pPlanet = self.getPlanet(iID) # post-change planet
		printd("  Adjusting stored production values for the city based on new build planet's data")
		for iBuilding in range(iNumBuildingTypes):
			pCity.setBuildingProduction(iBuilding, pPlanet.getBuildingProduction(iBuilding))
			printd("    building type %d set to %d" %(iBuilding, pPlanet.getBuildingProduction(iBuilding)))
		
		if (CyInterface().isCityScreenUp()):
			CyInterface().setDirty(InterfaceDirtyBits.CitizenButtons_DIRTY_BIT, True)
			CyInterface().setDirty(InterfaceDirtyBits.InfoPane_DIRTY_BIT, True)

That should do the trick.

Not quite as good as being able to queue things up for different planets at the same time, but one little irritating thing done away with.
 
That does not seem to be related to the production save issue/fix.

Line 869 in CvAI in B5v2.0 is dealing with checking to see if it should force the AI to build a carrier unit. Looking at it, there is not any check to make sure the civilization has a carrier unit so it can be feeding an invalid (-1) unit type value to pPlayer.canTrain. It assumes that everybody has a unit of unit class UNITCLASS_CARRIER_I that it is possible for them to build at some point (i.e. such a unit exists even if it can't currently be built).

The easiest fix is to make it not do any checking if there is no such unit.

Current line 869:
Code:
							if ( pPlayer.canTrain( iCarrierIUnit, true, false) ) :

New line 869:
Code:
							if ( (iCarrierIUnit != -1) and pPlayer.canTrain( iCarrierIUnit, true, false) ) :
That should take care of that problem for the carrier I unit class.

Inside that if block it also checks for unit of class UNITCLASS_CARRIER_II and UNITCLASS_CARRIER_III to pick the highest one the player can build. You may need to do a similar fix for them too, in case a civ doesn't have a unit for one or more of the other two carrier generations, on lines 910 and 912 although if it doesn't have the first one it never checks for the others. It may also need checks added in the part of the code that tries to count the number of existing units on lines 860-863.

There can also be an issue with the civics. The code is assuming the existence of the squadron doctrine civic, adjusting the probability of forcing the build of a carrier up if the civ is using it.

I would note that all that carrier production forcing code is not really useful at this time due to the problem that it never puts squadrons on carriers. Because of that, actually forcing it to build them is a waste of production in regular FFP since the carriers there have minimal direct combat ability. This is why the probabilities are mostly set to 0 unless the doctrine is being used, in which case it will tend to eventually force a few of them to be built. The AI in FFP does not normally select the Squadron Doctrine civic very often, so it does not normally force any carriers to be built due to the current probabilities that are in there.

After all that, you may also run into an issue with the squadrons. The code currently assumes the existence of 3 generations of fighter squadrons and 3 generations of bomber squadrons, plus a 4th generation (the Q squadron) which can functions as both fighter and bomber squadron. As with the carrier ship classes, it never checks to make sure that the civilization actually has a unit of the specified unit classes.
 
Thanks God-Emperor, this explains a great deal. In the B5 mod all of the UNITCLASS_CARRIER_I, II and III's have been removed or replaced with Unique units that no longer have the designation UNITCLASS_CARRIER_I.
Sounds like I need to go through that section and put in the names of all the different Civs carriers.
I've also changed the Squadron Doctrine Civic to Full Mobiilization so again, i'll need to check this and ensure it's not trying to do something i've made changes too.
 
Tried to install Final Frontier Plus (FFP) today for a change. Did not work - no text in main menu and in game. Game does render units/colonies/etc. Figured it was due to BUG/BULL and a messed up BAT deinstallation.

Therefore did a clean install of Civ 4, BTS, 3.19 patch and FFP. Only other mod installed was the German community translation. Problem persists.

First installed the small version of the mod and the patch. Problem occurred. Then installed the large version over the patch/small version, figuring maybe some resources were missing. Problem persists.

Final Frontier "classic" (started from BTS main menu) works flawlessly.

OS: Win 7 64 Bit

Any help would be appreciated :)
 
Are you set to use a language other than English in the game?

If so, that is probably the problem. Try switching to English. A few of the text entries don't have any entries for languages other than English, which just completely messes up Civ when running with it set to anything other than English.
 
That helped, thank you.

Maybe there is some way for the mod to force Civ IV to start with the language already set to English? Final Frontier classic seems to do this - at least the in-game text is English.
 
Final Frontier classic simply uses English text for all of the language options. But a lot of us got lazy and never defined text for the other language options.

Heh. By "some of us", you mean me (at least where FF+ is concerned). ;)

I'm fixing this now. I keep meaning to write a script to automate this tedious process (loop over text file, add in other language tags), but I can't be bothered to. Even though actually writing that would be far less work than fixing all my lazy text files.
 
I just hit a small bug. I'm amazed I've never seen it before.

The issue is that the AI production override Python routine has a problem for the Pirate controlled star systems. Specifically, the code tries to check to see if the civilization's unit type for the first generation fighter class can be trained but the Pirates are forbidden to build them. This means their civ's unit type for that is "-1" (for no such unit) and a call to the pPlayer.canTrain() function is passing that invalid "-1" value for the unit type to the DLL which causes the call to fail. The call failing certainly causes the Python function to exit prematurely, but does not crash the game (so if you do not have the Python exception reporting turned on, you'd never know it was happening).

The problem is line 925 of CvAI.py and it is easy to fix.
Original:
Code:
						if ((not bOverride) and ( pPlayer.canTrain( iSpaceFighterIUnit, true, false) ) ) :
Fixed:
Code:
						if ((not bOverride) and (iSpaceFighterIUnit != -1) and ( pPlayer.canTrain( iSpaceFighterIUnit, true, false) ) ) :

Since Python uses short-circuiting in its boolean evaluations, if the new second condition is false it will never actually do the call to canTrain so it won't fail.

There exists a second place where a nearly identical thing is done, for bomber squadrons rather than fighter squadrons. This should also be fixed like so:

Original line 972:
Code:
							if ((not bOverride) and ( pPlayer.canTrain( iSpaceBomberIUnit, true, false) ) ) :
Fixed line 972:
Code:
							if ((not bOverride) and (iSpaceBomberIUnit != -1) and ( pPlayer.canTrain( iSpaceBomberIUnit, true, false) ) ) :

There still exist potential problems if there exists a civilization that can produce a first generation squadron but not one or more of the later generations. This is not an issue for FFP, since there is no such civilization, but if the same code is used in another mod then it could be an issue. In that case, similar checks should be done in a number of other places in the part of the code.
 
The only thing I can think of is that you somehow have a planet that was not created properly or (more likely, I think) has been modified incorrectly, such that it has its data set to indicate that it has no iPopulation value. Perhaps somewhere something is setting the population of a planet to None instead of 0? I'm not sure if that will actually give this specific error (since it may not actually remove the attribute from the object). Doing a "del pPlanet.iPopulation" somewhere would give this error.
 
I have encountered a Leaderhead CtD ... I'll try to determine which one.

Btw: Excellent modmod. My Civ4 addiction continues for another year or so.
 
Its nice that the mod is faster as the origin, but is it possible to get the the star systems preview back? Or is it only for me not working?
 
The star system preview should work the same as always. Double click on a star that is not shown as being inside someone's cultural borders.
 
OK, here we go: bugs for 1.7
(This is a pretty long message... Some of the stuff is not very significant, others more so.)

I have not actually played yet, I just went through and clicked on everything in the Sevopedia from the main menu.

Clicking on any leader in the list in the Leaders category gives a Python error about "'CvLeaderHeadInfo' has no attribute 'getFavoriteCivic'". I would assume that the multiple favorite civic mod changed how this works, or something along those lines. THis makes it stop displaying things so the screen doesn't show a lot of the information.

The list in the Traits category is empty. The Shortcuts category is empty. The Strategy Guides category is empty (possibly a good thing since the guides are all for regular BtS).
- I checked, and 1.7 does not have the updated Python\BUG\TraitUtil.py file that is in the FFPBUG beta which defines the FFP traits and gives them icons. It also does not have the changes to XML\BasicInfos\CIV4NewConceptInfos.xml that enable the Sevopedia Trait related stuff. The version in FFPBUG bet has a bunch of commented out stuff but also some addional stuff that is not (all the standard traits are in there but commented out, along with new entries for the FFP traits - note that they have to be in alphabetical order; I left the regular traits in there in the correct order but commented out in case the secondary traits that I used in Finaler Frontier are added). Likewise the 1.7 CIV4NewConceptInfos.xm does not have the entries that define the shortcuts or the strategy guides (which can be left out as most of them are not applicable). The Sevopedia uses the second word in the type name to categorize the concepts (CONCEPT_x_SOMETHING is associated with the category for "x" in the Sevopedia contents list). Also part of this is the file XML\Text\TraitsPedia_CIV4GameText.xml to which the FFPBUG beta added a text key for each of the FPP traits (this stuff is not in the 1.7 version of it).

The Corporations section is also empty, but that is not surprising since we have no corporations and it is therefor not a bug.


Other modified files in the FFPBUG beta that didn't make it in, many of which could lead to bugs:

- in XML\GameInfo\CIV4CivicInfos.xml the 3 military doctrines which give free unit support are back to using iBaseFreeMilitaryUnits isntead of iBaseFreeUnits. The military unit cost is only non-zero if running pacifism which, as it is also a military civic, can't be run at the same time as the others. That makes setting iBaseFreeMilitaryUnits useless (unless you changed what it does).

- 1.7's XML\GameInfo\CIV4CultureLevelInfo.xml is not the one from FFPBUG beta which bumped the values up for the higher culture levels and adjusted the Quick gamespeed's values to be more closely matching the others.


- the modified Python\Contrib\autologEventManager.py which does a couple of things:
-- adds the new goody types to the list for the autolog messages
--- associated with this is a new text file XML\Text\FFP BUG Text.xml which defines the text keys for the new autolog messages (plus a new help message for the mining facility that explains that the Forge gets +2 production for the planet instead of +1)
-- removes the hardcoding that specifies 5 civic categories, replacing the "5" with a lookup for the actual number in four places in the file


- the modified Python\Contrib\UnitNameEventManager.py file which enables the Advanced Unit Naming BUG option to work properly when there are delta and omega characters in the unit's type

- the modified Python\EntryPoints\CvRandomEventInterface.py file with the Partisan event fixes

- the modified Python\pyWB\CvWBDesc.py file which validates a team's existence before using the team object

- the modified Python\Screens\CvCustomizableDomesticAdvisor.py file which fixes the calculatePotentialConscriptUnit function so that when there is no conscriptable unit it will not attempt to use a method on the none type object

- the modified Python\Screens\CvExoticForeignAdvisor.py file with a fix to validate the player object to verify that it exists and the player is alive before trying to do things with it

- the modified Python\Screens\CvVictoryScreen.py file which forces the old-style "space ship" project victory screen text to be used since it comes out better than the BUG version (which does not give any useful information about the Astral Gate stuff).

- the modified Assets\Python\Screens\PLE.py file where I added some checks to fix the Python errors that can pop up in great quantities when you build a starbase while another ship is also on the plot (which I'm not sure has actually solved the problem of the apparently "half dead" construction ship).

- there are minor differences in Python\FinalFrontierEvents.py - I see you implemented the ting in my memory update notes about clearing the stored building production for captured planets. I also see that you did not include the team validation on the doAIWarChance that causes debug DLLs to have an assertion failure when not included.

As for the advanced station AI, the FFPBUG beta didn't have it. This the many discrepancies in CvAI.py.

- the Config\BUG Core.xml file in 1.7 does not have the Update event added to the noLogEVents list. This event happens, and therefore is logged, multiple times per second and therefore swamps all the others and makes it hard to find anything else.

A group of related things:
- the modified Python\Contrib\Sevopedia\SevoPediaTech.py file which enables the option to show, or not, the text for unresearched techs controlled from the new FFP tab in the BUG options screen. Likewise the new Python\BUG\Tabs\FFPOptionsTab.py file is missing- the Config\Final Frontier Plus.xml file does not have the section for the new BUG option screen tab for FFP. IT also has the version number still set to 1.651.
- the Config\init.xml file does not have the added option screen tab definition for FFP
- the new XML\Text\FFP Options.xml is missing, it defines the text used on the FFP options screen
(I assume that the new options tab was left out on purpose at this point. It only had the one option relating to the tech text display.)

In the Final Frontier Plus\UserSettings folder there are a number of files that are different:

Adv Unit Naming.ini should use the FFPBUG beta version (in the separate "optional" patch that is specifically for this) since the default one is empty which makes the Advanced Unit Naming option fail to produce useful results.

BUG Advisors.ini should have the GP Tech Prefs set to false to avoid having the great person bar on the left of the tech screen (useless since there are no great people) - this is a setting on the one of the BUG option screens and the value int his file is what it will start out as being set to when the game is first run, but it can be changed by the user should he or she desire to mess up the tech screen with what is useless junk in FFP.

BUG City Screen.ini in my versio has City Specialists set to 0 instead of 2. Since most (if not all) of the stuff on the city screen that would show specialists is currently commented out, I'm nost sure if this actually does anything at the moment.

FFP.ini is not present since you didn't add the FFP tab to the BUG options screen.

That's it for now (as if it isn't enough).
 
As usual... plenty of stupid things that I overlooked for a first patch.

I'll get 1.71 out either later today, or tomorrow once more reports come in.

I suspect that when I installed FFPBUG, I either never installed one of your patches, or I screwed up the installation (or perhaps the merge). So when I went to verify that I had everything merged by copying things from my FFPBUG directory, I didn't do a very good job of it. But in any case, I will fix that promptly- those Python (and XML) files, plus the FF+ tab, will be fixed in the next version.

I'm not sure what happened with the advanced station construction AI. I'm almost certain I did merge that into my working copy a while ago. So either I screwed it up while merging, or deleted it at some other point of this process; or maybe I'm just remembering wrong. :(

Multiple favorite civics does need to be changed for the pedia, you're correct.

EDIT: Re Station Construction AI:

What should this look like? Because this is what it looks like in the release folder for the 6 MB version, which was copied from the 30 MB version:

Spoiler :
Code:
	def findBestChokepoint(self, iPlayer=-1, bCheckForVisibility=false):
		"""Returns a tuple of the best chokepoint plot and its plot value."""
		pBestPlot = -1
		iBestValue = -1
		pPlayer = -1
		iTeam = -1
		if (iPlayer >= 0):
			pPlayer = gc.getPlayer(iPlayer)
			iTeam = pPlayer.getTeam()

		iFeatNebula = gc.getInfoTypeForString('FEATURE_ICE')
		iFeatAsteroid = gc.getInfoTypeForString('FEATURE_FOREST')
			
		iMaxRange = max(CyMap().getGridWidth() / 2, 60)
		printd("findBestChokepoint    iMaxRange = %d" % (iMaxRange))		
		for iPlotLoop in range(CyMap().numPlots()):
			pLoopPlot = CyMap().plotByIndex(iPlotLoop)
			
			# If we're supposed to be checking for a player's visibility then only check this plot if it's revealed
			if (bCheckForVisibility):
				if (not pLoopPlot.isRevealed(iTeam, false)):
					continue

			# CP - Check the plot being rated to see if it already belongs to someone else.
			iPlotOwner = pLoopPlot.getOwner()
			if ((iPlotOwner != -1) and (iPlotOwner != iPlayer)):
				continue

			# Don't build anywhere except in empty space & asteroids
			if (pLoopPlot.getFeatureType() != -1 and pLoopPlot.getFeatureType() != iFeatAsteroid):
				continue

			iDistanceFromCapital = CyMap().getGridWidth()
			
			if (pPlayer.getCapitalCity()):
				iDistanceFromCapital = CyMap().calculatePathDistance(pPlayer.getCapitalCity().plot(), pLoopPlot)
			
			# Don't look too far away (performance, more than anything)
			if (iDistanceFromCapital > 0 and iDistanceFromCapital < iMaxRange):
				
				if iDistanceFromCapital < 4 : # Discourage it from building sensor stations right next to the capital
					iDistanceValueMod = -9    # it will also get a penalty down below for being close to a star system if it is within 2
				else : # Highest distance scores in the zone from 1/6 iMaxRange to 2/3 iMaxRange, in this zone iDistanceValueMod will be iMaxRange/6
					iDistanceValueMod =  ((2 * min( iDistanceFromCapital, iMaxRange/6)) - max( iDistanceFromCapital - (2 * iMaxRange / 3), 0)) / 2
				
				iPlotValue = 0
				iNumNebula = 0
				iNumAdjacentNebula = 0
				iNumAsteroid = 0
				iNumDamaging = 0
				for iXSearchLoop in range(pLoopPlot.getX()-2, pLoopPlot.getX()+3):
					for iYSearchLoop in range(pLoopPlot.getY()-2, pLoopPlot.getY()+3):
						# If the map does not wrap and the plot is not on the map give a small penalty and skip to the next.
						# Note that if the plot is off the map then all plots in that row and/or column are off too
						# so it will actually be at least 5 plots that give this penalty.
						if not CyMap().isPlot(iXSearchLoop, iYSearchLoop):
							iPlotValue -= 3
							continue
							
						pSearchPlot = CyMap().plot(iXSearchLoop, iYSearchLoop)
						
						# Don't search unseen plots in range of the one we're looking at either
						if (bCheckForVisibility):
							if (not pSearchPlot.isRevealed(iTeam, false)):
								continue

						#Build sensor stations near chokepoints -- TC01
						iFeature = pSearchPlot.getFeatureType()
						if iFeature == iFeatNebula:
							iNumNebula += 1
							if (abs(iXSearchLoop - pLoopPlot.getX()) <= 1) and (abs(iYSearchLoop - pLoopPlot.getY()) <=1):
								iNumAdjacentNebula += 1
						elif iFeature == iFeatAsteroid:
							iNumAsteroid +=1
						elif (iFeature != -1) and (gc.getFeatureInfo(iFeature).getTurnDamage() > 0): # bug fix - make sure there is a feature before trying to get the info for it, taking advantage of the short-circuit conditional evaluation
							iNumDamaging += 1
						elif iFeature == gc.getInfoTypeForString('FEATURE_SOLAR_SYSTEM'):
							iPlotValue -= 22 # reduce value a lot if near a star system
						
						#If other stations are present, no build -- TC01
						for iUnit in range(pSearchPlot.getNumUnits()):
							pOtherStarbase = pSearchPlot.getUnit(iUnit)
							if pOtherStarbase.isStarbase():
								# iPlotValue = 0
								iPlotValue -= 99
								break

				# Some nebula is a good indication of a choke point.
				# Too much is an indication that we are in a box canyon.
				# If there are 7 or more adjacent nebula plots, then this is a bad location. Otherwise:
				# As a guess, make it increase the value for more up to a max value at 13, then decrease fairly rapidly.
				# Give a score of 0 for 0, increaseing by 3 per nebula up to a score of 39 at 13 through 15,
				# then decreasing by 5 per nebula over 15.
				# This is -1 at 23, -6 at 24 and -11 at 25 (which is not a valid location anyway; neither is one
				# with 23 or 24 since it is unreachable from the capital so the iDistanceFromCapital condition
				# rules it out before we get here).
				# Additionally, if there are more than 4 (i.e. 5 or 6) immediately adjacent nebula plots, give a
				# small penalty of -2.
				if iNumAdjacentNebula > 6 :
					iPlotValue -= 99
				else:
					iPlotValue += ( 3 * min( iNumNebula, 13)) - ( 5 * max( iNumNebula - 15, 0))
					if iNumAdjacentNebula > 4 :
						iPlotValue -= 2 

				# A few asteroids are OK, but they block the visibility (and visibility is the whole point of a sensor station)
				# With 0 no change, then +5 for 1-3 (which is the max bonus), then -1 for each over 3.
				# Note that there is still a bonus for being on top of asteroids given later.
				iPlotValue += ( 5 * min( iNumAsteroid, 1)) - max( iNumAsteroid - 3, 0)
				
				# Damaging features are good, but too many is not as good since the area will tend to be avoided and
				# it is probably between two black holes/supernovas (which is a good chokepoint, but bad for the visibility
				# aspect since looking at a lot of such plots is rather pointless).
				# Give +2 per, up to a max of +30 at 15, then -1 per damaging feature over 15
				iPlotValue += ( 2 * min( iNumDamaging, 15)) - max( iNumDamaging - 15, 0)
				
				iPlotValue += iDistanceValueMod

				# Little extra bonus for being in Asteroids (defense)
				if (pLoopPlot.getFeatureType() == iFeatAsteroid):
					iPlotValue += 4		#How small should it be?

				# If this plot has the most resources in range from what we've found
				if (iPlotValue > iBestValue):
					iBestValue = iPlotValue
					pBestPlot = pLoopPlot
				
				printd("plot %d (%d,%d) value = %d (distance=%d (for %d), NumNebula=%d (adjacent=%d), NumAsteroid=%d, NumDamaging=%d)" % 
						(CyMap().plotNum(pLoopPlot.getX(), pLoopPlot.getY()), pLoopPlot.getX(), pLoopPlot.getY(), 
						iPlotValue, iDistanceFromCapital, iDistanceValueMod, iNumNebula, iNumAdjacentNebula, iNumAsteroid, iNumDamaging))
					
		printd("* best plot = %d (%d,%d), value = %d" % (CyMap().plotNum(pBestPlot.getX(), pBestPlot.getY()), pBestPlot.getX(), pBestPlot.getY(), iBestValue))
			
		return [pBestPlot, iBestValue]

Did you change it more than this? I don't remember.

WinMerge also has no significant differences between FFPBUG's CvAI.py and mine other than this area of the function (which is mostly yellow, to be fair, because station construction AI changed it a lot).

EDIT 2: Cleaned up all of this except the leaderhead infos. Unless there's a drastic error you find when you actually start playing (and at this rate I wouldn't be surprised :( ), I'll release a patch with all of this later today.
 
About the advanced station AI: I was just pointing out that it is in 1.7 but was not in the FFPBUG beta which is why there are a bunch of differences between the CvAI.py file in 1.7 and the one in my beta. I think it is all in there, but I didn't look closely.

Aside from the findBestChokepoint function, there was the change to the part of doStationConstructionAI for selecting the station type which involved converting the class to the type for the unit to produce (which included the code that would make UU stations/starbases work too, as seen back in post 112 of this thread) and there is also a different version of the canConstructSensorStation function that uses a shifting (or "floating", as I was calling it) threshold for deciding if a station should be built (since the maximum plot rating is unknown for a random map and the distribution of the ratings will vary from map to map and with mapscript type as well, this version is probably better - it initially sets the threshold for building a station somewhat low, but much higher than it had been, and bumps it up for each station built to try to keep it from building too many - there is probably a better way involving doing a pass over the map to rate the plots at the start of the game to figure out what the threshold should be, but this was a lot easier and is a lot faster).

There were also some bug fixes to get it working in the first place (as per post 76 in the Modder's Guide thread) but I think you have them, and shifting the initialization time of CvAI which you also have in 1.7 already.
 
Top Bottom