• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

Bug Thread

I have worked my way through the assert failures. Some of them point to real problems, some don't. Any that pointed to real problems got fixed.

Theoretically, the first issue (TRAIT_*) may be a minor problem, but I didn't feel like tracking down which XML file was being defaulted to a BtS (or Warlords, or Vanilla)
XML file that was using them. If my secondary traits are ever added back in, it will
no longer be an issue since they have all the same names as the regular traits.

Anyhow, this is what I found:
Code:
			ON LOAD:

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_AGGRESSIVE not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_CHARISMATIC not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_CREATIVE not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_FINANCIAL not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_IMPERIALIST not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_INDUSTRIOUS not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------


			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_ORGANIZED not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_PHILOSOPHICAL not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_PROTECTIVE not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml

			----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvglobals.cpp
			Line:  3493
			Expression:  strcmp(szType, "NONE")==0 || strcmp(szType, "")==0
			Message:  info type TRAIT_SPIRITUAL not found, Current XML file is: xml\GameInfo/CIV4EspionageMissionInfo.xml



None of the above are what they seem. The TRAIT_* text appears nowhere in
CIV4EspionageMissionInfo.xml, which is a file that is not present in FFP
(with BUG or not) and is therefore defaulting to the one from BtS.
These are all reported in xml.log a the very end so it is claiming
this as the XML file just because it was the last one that is read
and these come after that (presumably in some readpass2 or 3 type
function for resolving the interfile dependencies).

Since these TRAIT_* strings don't occur anywhere in FFP's XML files
other than some commented out sections of CIV4BuildingInfos.xml they
must be in an XML file that is being defaulted to the BtS (or earlier)
version.

----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvplayer.cpp
			Line:  11669
			Expression:  eIndex < GC.getNumCivicOptionInfos()
			Message:  eIndex is expected to be within maximum bounds (invalid Index)

This is a BUG bug.
			
In autologEventManager.py there are hardcoded loops that go over 5 
civicoption types when FFP only has 4 civicoption categories. This is
used to store civic options for each civ and check to see if they have
changed and such.

Relevant code is all over the place, about everywhere the self.CIVCivics
variable is used including its initialization.

Instead of using "5" it needs to use the actual number as returned by
gc.getNumCivicOptionInfos() in a bunch of places.

----------------------------------------------------------

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvteam.cpp
			Line:  3451
			Expression:  eIndex >= 0
			Message:  eIndex is expected to be non-negative (invalid Index)

This assert is in CvTeam::isHasMet.
			
This is probably an FF bug. Or two+, actually. In FinalFrontierEvents.py (and
CvFinalFrontierEvents.py in FFP and FF) in the doAIWarChance function it
is looping over all possible teams via
"for iLoopTeam in range(gc.getMAX_CIV_TEAMS()):"
but it never checks to see if the team number it is checking is alive or
has ever been alive. It gets the team leader for each, so it should check
that player to see if they exist and are alive before it uses the team ID.

A similar set of loops is used in CvWBDesc.py. There are no checks of any
sort run to see if the returned number is a valid team. These not only
use the isHasMet function, but various others like isVassal and
getEspionagePointsAgainstTeam.

BUG's CvExoticForeignAdvisor does this in one location too, in drawInfoImproved
it is looping over all possible players without checking them to see if they
are valid before getting the TeamInfo and calling isHasMet.

Fixes have been put in place for all of them that I found.

Since this was happening on load, I think this would have been the CvWBDesc.py
issue, but if that is the case I don't know why the functions other than isHasMet
didn't fire off their asserts too.

----------------------------------------------------------

			ON CLICKING NEXT TURN:

			Assert Failed

			File:  f:\civilization 4 mods\sdk stuff\dll 1 bts\1.651 debug dll\cvgamecoredll\cvcity.cpp
			Line:  1096
			Expression:  iCount == getBaseYieldRate((YieldTypes)iI)
			Message:  

This is spurious. It is in a chunk of code that is only compiled for a debug
build which is apparently recalculating the the city's total base yields
(as the sum of the output from worked plots, specialists, buildings, trade
routes, and corporations) and comparing this local calculation to what
getBaseYieldRate returns. The calculation it does is evidently not including
everything that FFP does to get its base yields.
 
I believe when the failures occur in EspionageMissionInfos, they're really occuring in Python somewhere- that is the last XML file to get loaded, so assert failures that are happening in Python (I think) get attributed to it.

Thanks for looking into it!
 
I looked at the doGravityField code so I can fix the bug in Star Trek, but it appears as if the code doesn't compensate for the map wrap at all! Please correct me if I'm wrong, but I didn't see anything indicating wrap corrections. Does the function to get the plot already compensate for wrapping?
 
The function plotINLINE() does adjust the coordinates for wrap to get you the correct plot via the coordRange() function calls. Both of these functions are defined in CvMap.h (not .cpp).
 
I've come across an error whilst play testing the B5 mod. When you first start playing and building up your planetary infrastructure the number of hammers remains stable (see pics 1,2 and 3) until the Recycling Center is built (see pic 4) when the production shoots up to a huge figure making it possible to churn out a lot more buildings & ships early on, for some reason the production drops back down to a more normal figure after you have built your 2nd recycling centre.
Here is the building infos XML for the recycling centre we use in the mod.

Code:
		<BuildingInfo>
			<BuildingClass>BUILDINGCLASS_RECYCLING_CENTER</BuildingClass>
			<Type>BUILDING_RECYCLING_CENTER</Type>
			<SpecialBuildingType>NONE</SpecialBuildingType>
			<Description>TXT_KEY_BUILDING_RECYCLING_CENTER</Description>
			<Civilopedia>TXT_KEY_BUILDING_RECYCLING_CENTER_PEDIA</Civilopedia>
			<Strategy>TXT_KEY_BUILDING_RECYCLING_CENTER_STRATEGY</Strategy>
			<Help/>
			<Advisor>ADVISOR_GROWTH</Advisor>
			<ArtDefineTag>ART_DEF_BUILDING_RECYCLING_CENTER</ArtDefineTag>
			<MovieDefineTag>NONE</MovieDefineTag>
			<HolyCity>NONE</HolyCity>
			<ReligionType>NONE</ReligionType>
			<StateReligion>NONE</StateReligion>
			<bStateReligion>0</bStateReligion>
			<PrereqReligion>NONE</PrereqReligion>
			<PrereqCorporation>NONE</PrereqCorporation>
			<FoundsCorporation>NONE</FoundsCorporation>
			<GlobalReligionCommerce>NONE</GlobalReligionCommerce>
			<GlobalCorporationCommerce>NONE</GlobalCorporationCommerce>
			<VictoryPrereq>NONE</VictoryPrereq>
			<FreeStartEra>NONE</FreeStartEra>
			<MaxStartEra>NONE</MaxStartEra>
			<ObsoleteTech>NONE</ObsoleteTech>
			<PrereqTech>TECH_B5_ADVANCED_RECYCLING</PrereqTech>
			<TechTypes/>
			<Bonus>NONE</Bonus>
			<PrereqBonuses/>
			<ProductionTraits/>
			<HappinessTraits/>
			<NoBonus>NONE</NoBonus>
			<PowerBonus>NONE</PowerBonus>
			<FreeBonus>NONE</FreeBonus>
			<iNumFreeBonuses>0</iNumFreeBonuses>
			<FreeBuilding>NONE</FreeBuilding>
			<FreePromotion>NONE</FreePromotion>
			<CivicOption>NONE</CivicOption>
			<GreatPeopleUnitClass>NONE</GreatPeopleUnitClass>
			<iGreatPeopleRateChange>0</iGreatPeopleRateChange>
			<iHurryAngerModifier>0</iHurryAngerModifier>
			<bBorderObstacle>0</bBorderObstacle>
			<bTeamShare>0</bTeamShare>
			<bWater>0</bWater>
			<bRiver>0</bRiver>
			<bPower>0</bPower>
			<bDirtyPower>0</bDirtyPower>
			<bAreaCleanPower>0</bAreaCleanPower>
			<DiploVoteType>NONE</DiploVoteType>
			<bForceTeamVoteEligible>0</bForceTeamVoteEligible>
			<bCapital>0</bCapital>
			<bGovernmentCenter>0</bGovernmentCenter>
			<bGoldenAge>0</bGoldenAge>
			<bAllowsNukes>0</bAllowsNukes>
			<bMapCentering>0</bMapCentering>
			<bNoUnhappiness>0</bNoUnhappiness>
			<bNoUnhealthyPopulation>0</bNoUnhealthyPopulation>
			<bBuildingOnlyHealthy>0</bBuildingOnlyHealthy>
			<bNeverCapture>0</bNeverCapture>
			<bNukeImmune>0</bNukeImmune>
			<bPrereqReligion>0</bPrereqReligion>
			<bCenterInCity>0</bCenterInCity>
			<iAIWeight>0</iAIWeight>
			<iCost>40</iCost>
			<iHurryCostModifier>0</iHurryCostModifier>
			<iAdvancedStartCost>50</iAdvancedStartCost>
			<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>
			<iMinAreaSize>-1</iMinAreaSize>
			<iConquestProb>50</iConquestProb>
			<iCitiesPrereq>0</iCitiesPrereq>
			<iTeamsPrereq>0</iTeamsPrereq>
			<iLevelPrereq>0</iLevelPrereq>
			<iMinLatitude>0</iMinLatitude>
			<iMaxLatitude>90</iMaxLatitude>
			<iGreatPeopleRateModifier>0</iGreatPeopleRateModifier>
			<iGreatGeneralRateModifier>0</iGreatGeneralRateModifier>
			<iDomesticGreatGeneralRateModifier>0</iDomesticGreatGeneralRateModifier>
			<iGlobalGreatPeopleRateModifier>0</iGlobalGreatPeopleRateModifier>
			<iAnarchyModifier>0</iAnarchyModifier>
			<iGoldenAgeModifier>0</iGoldenAgeModifier>
			<iGlobalHurryModifier>0</iGlobalHurryModifier>
			<iExperience>0</iExperience>
			<iGlobalExperience>0</iGlobalExperience>
			<iFoodKept>0</iFoodKept>
			<iAirlift>0</iAirlift>
			<iAirModifier>0</iAirModifier>
			<iAirUnitCapacity>0</iAirUnitCapacity>
			<iNukeModifier>0</iNukeModifier>
			<iNukeExplosionRand>0</iNukeExplosionRand>
			<iFreeSpecialist>0</iFreeSpecialist>
			<iAreaFreeSpecialist>0</iAreaFreeSpecialist>
			<iGlobalFreeSpecialist>0</iGlobalFreeSpecialist>
			<iMaintenanceModifier>0</iMaintenanceModifier>
			<iWarWearinessModifier>0</iWarWearinessModifier>
			<iGlobalWarWearinessModifier>0</iGlobalWarWearinessModifier>
			<iEnemyWarWearinessModifier>0</iEnemyWarWearinessModifier>
			<iHealRateChange>0</iHealRateChange>
			<iHealth>1</iHealth>
			<iAreaHealth>0</iAreaHealth>
			<iGlobalHealth>0</iGlobalHealth>
			<iHappiness>1</iHappiness>
			<iAreaHappiness>0</iAreaHappiness>
			<iGlobalHappiness>0</iGlobalHappiness>
			<iStateReligionHappiness>0</iStateReligionHappiness>
			<iWorkerSpeedModifier>0</iWorkerSpeedModifier>
			<iMilitaryProductionModifier>0</iMilitaryProductionModifier>
			<iSpaceProductionModifier>0</iSpaceProductionModifier>
			<iGlobalSpaceProductionModifier>0</iGlobalSpaceProductionModifier>
			<iTradeRoutes>0</iTradeRoutes>
			<iCoastalTradeRoutes>0</iCoastalTradeRoutes>
			<iGlobalTradeRoutes>0</iGlobalTradeRoutes>
			<iTradeRouteModifier>0</iTradeRouteModifier>
			<iForeignTradeRouteModifier>0</iForeignTradeRouteModifier>
			<iGlobalPopulationChange>0</iGlobalPopulationChange>
			<iFreeTechs>0</iFreeTechs>
			<iDefense>0</iDefense>
			<iBombardDefense>0</iBombardDefense>
			<iAllCityDefense>0</iAllCityDefense>
			<iEspionageDefense>0</iEspionageDefense>
			<iAsset>2</iAsset>
			<iPower>0</iPower>
			<fVisibilityPriority>1.0</fVisibilityPriority>
			<SeaPlotYieldChanges/>
			<RiverPlotYieldChanges/>
			<GlobalSeaPlotYieldChanges/>
			<YieldChanges>
				<iYield>1</iYield><!-- Food -->
				<iYield>1</iYield><!-- Hammers -->
				<iYield>1</iYield><!-- Credits -->
			</YieldChanges>
			<CommerceChanges/>
			<ObsoleteSafeCommerceChanges/>
			<CommerceChangeDoubleTimes/>
			<CommerceModifiers/>
			<GlobalCommerceModifiers/>
			<SpecialistExtraCommerces/>
			<StateReligionCommerces/>
			<CommerceHappinesses/>
			<ReligionChanges/>
			<SpecialistCounts/>
			<FreeSpecialistCounts/>
			<CommerceFlexibles/>
			<CommerceChangeOriginalOwners/>
			<ConstructSound>AS2D_BUILD_RECYCLING_CENTER</ConstructSound>
			<BonusHealthChanges/>
			<BonusHappinessChanges/>
			<BonusProductionModifiers/>
			<UnitCombatFreeExperiences/>
			<DomainFreeExperiences/>
			<DomainProductionModifiers/>
			<BuildingHappinessChanges/>
			<PrereqBuildingClasses/>
			<BuildingClassNeededs/>
			<SpecialistYieldChanges/>
			<BonusYieldModifiers/>
			<ImprovementFreeSpecialists/>
			<Flavors>
				<Flavor>
					<FlavorType>FLAVOR_GROWTH</FlavorType>
					<iFlavor>10</iFlavor>
				</Flavor>
			</Flavors>
			<HotKey/>
			<bAltDown>0</bAltDown>
			<bShiftDown>0</bShiftDown>
			<bCtrlDown>0</bCtrlDown>
			<iHotKeyPriority>0</iHotKeyPriority>
			<iCostModIncrease>2</iCostModIncrease>
		</BuildingInfo>
If you have any ideas as to what may be causing the jump in production i would love to hear them.

P.S. Although my primary concern was the production/hammers the food production is similarly affected.
 
This looks like an issue that was fixed in v1.65 of FFP.

The issue is that the counters in the CvCity::doTurn() function where it is calculating the base yield levels are not zeroed properly.

Based on your note in the mod, you are using the v3 version of your DLL. In there you have this:
Code:
	CvPlayer& pPlayer = GET_PLAYER(getOwner());
	int iYield = 0;
	int iBuildingYield = 0;
	int iTraitYield = 0;
	setFoodOverride(0);
	setProductionOverride(0);
	setGoldOverride(0);
	for (int iYieldLoop = 0; iYieldLoop < NUM_YIELD_TYPES; iYieldLoop++)
	{
		//Reset iYield to 0
		iYield = 0;

		//Building yields
		for (int iBuilding = 0; iBuilding < GC.getNumBuildingInfos(); iBuilding++)
		{
			BuildingTypes eBuilding = (BuildingTypes)iBuilding;
			if (getNumRealBuilding(eBuilding) > 0)
			{
				iBuildingYield = GC.getBuildingInfo(eBuilding).getYieldChange(iYieldLoop) * getNumRealBuilding(eBuilding);
			}
			iYield += iBuildingYield;
		}
Note that iBuildingYield is zeroed before the loop for the yield types. It is not zeroed again after that. The first time it finds a building with a yield of the current type it sets iBuildingYield to a non-zero value. That value is then added to the iYield for every single building in the loop after that that does not exist in the city. Once it hits another building that is in the city iBuildingYield is set to whatever the yield for that building is (often, but not always 0). Note that the value is also not zeroed when you loop to the next yield type, so the problem carries over to the later yield types from the earlier ones. Since the order is food, production, then commerce it is typically commerce that gets the worst of it.

The other parts of this function that do similar things for traits and trade routes don't really have this problem because of the details of the code.

This section of code was modified in 1.65 so that it doesn't have this problem. For the sake of compatibility you should probably go with the code from 1.65 instead of implementing you own fix. (It was fixed by eliminating the temporary accumulation variable, iBuildingYield. Instead, it just directly adds to iYield.)
 
I guess i must have missed that little update, best i go try and fix it now then lol.

OK, i've merged in the 1.65 & 1.651 patches and the Mod now runs with no CTD's. However, there is another glitch that has appeared and is similar to one i've had before. In the attached Pic you'll see that the error is an on game start one. Line 170 in my CvFinalFrontierEvents.PY file is
Code:
pAlien = CyMap().plot(i)
. From this I think the answer will be in a map script somewhere. Any suggestions on how to fix this?
 
I have figures out why it is building two things at one place.

The thing is that it thinks it is building only outposts. The reason for this is that the ImprovementInfo stores the unit class to make, but the code is taking that number and using it as the unit type. This makes its checks use a semi-random unit. The check does a "if (pUnitInfo.isStarbase() and not pUnitInfo.isOtherStation()):" on this semi-random pUnit, which (not surprisingly) fails. It then falls through to the "else" part which calls canConstructSensorStation. It is never using canConstructStarbase.

To fix this, I made it get the unit type for the unit class that is appropriate for the civ in question (so it should work even for a starbase UU). The start of the doStationConstructionAI function now looks like this:
Code:
	def doStationConstructionAI(self, pUnit, iBuild):
		"""This function decides what set of other functions to run depending on what the station type is."""
		pBuildInfo = gc.getBuildInfo(iBuild) # bug fix - was using the non-existent "iStation" instead of iBuild
		pImprovementInfo = gc.getImprovementInfo(pBuildInfo.getImprovement())
		[COLOR="DarkRed"][B]pCivilization = gc.getCivilizationInfo(pUnit.getCivilizationType())[/B][/COLOR] # bug fix - part of the fix for the next line
		[COLOR="DarkRed"][B]pUnitInfo = gc.getUnitInfo(pCivilization.getCivilizationUnits(pImprovementInfo.getUnitClassBuilt()))[/B][/COLOR] # bug fix -  was doing the getUnitInfo on the unit class directly
		pPlayer = gc.getPlayer(pUnit.getOwner())
		pTeam = gc.getTeam(pPlayer.getTeam())

Ran the same turn from the same save as before and now everybody is sending construction ships to two different places. The sensor station locations are still the dead-end-hole-in-a-nebula type places, but the designated starbase builders are headed towards the more usual, and useful, types of places.

I will be posting some improved choke-point locater code soon. It still won't be great, but it will be better.
 
Okay, installed the fix, from post #89 to the 1.651 version i am now running but it has thrown up an error on the next line down, see attached pic. I've looked through the posts and can see no mention of this problem. Line 171 is as follows
Code:
if pAlien.getFeatureType() == self.iFeatureIDSolarSystem:
Any suggestions?
 
Odd. It ought to be defined on the immediately preceding line.
Code:
				pAlien = CyMap().plotByIndex(i)
				if pAlien.getFeatureType() == self.iFeatureIDSolarSystem:
The question is, what did you do to the code since v2.0? The code in B5 v2.0, retrieved from the link in your PM, is working (and has the "plotByIndex" fix in it already too, since the lines above were copied from there).
 
Thanks for the above, i've checked my entries again and it looks like there was an indent where there shouldn't have been, i've corrected it now and hopefully that should be me ready to upload the corrected B5 V2.0

I'll re test in the morning as it's getting late here.
 
I have an updated location finder for the "other" type base, v a new perhaps not quite accurately named (based on actual functionality rather than desired functionality) findBestChokepoint function.

This is better than the original, but it is still not exactly what I'd call "good".

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]

This function seems to max out at a rating of 52 on the map in the Galaxy scenario.

I suggest changing the threshold in the canConstructSensorStation from 10 up to 45, on the "if (iBestValue > 10)" line.

I think it might also be a good idea to have the threshold adjusted so that it increases by 1 per sensor station that has already been built. If this is not done, the AIs could ruin their economies on a large map like the Galaxy map by building lots of sensor stations (which are then wiped out by hostile enemies and others since they are strength 0 and the AI doesn't appear to send any ships to protect them).

The floating threshold version of canConstructSensorStation looks like this:
Code:
	def canConstructSensorStation(self, pUnit, iBuild):
		"""This function checks if the AI can build a sensor station - it uses specific sensor station checks"""
		bValid = false
		pBestPlot, iBestValue = self.findBestChokepoint(pUnit.getOwner(), true) # bug fix - was trying to use non-existent iPlayer
		if (pBestPlot != -1):
			iX = pBestPlot.getX()
			iY = pBestPlot.getY()

			pBuildInfo = gc.getBuildInfo(iBuild)
			pImprovementInfo = gc.getImprovementInfo(pBuildInfo.getImprovement())
			pCivilization = gc.getCivilizationInfo(pUnit.getCivilizationType())
			iBuildUnit = pCivilization.getCivilizationUnits(pImprovementInfo.getUnitClassBuilt())
			pyPlayer = PyPlayer(pUnit.getOwner())
			apUnitList = pyPlayer.getUnitsOfType(iBuildUnit)
			iThreshold = 45 + len(apUnitList)
			printd("canConstructSensorStation: threshold=%d, best=%d" % (iThreshold, iBestValue))
			if (iBestValue > iThreshold):	# was 10 with old system		#What should be the cutoff for a really good value?
				bValid = True
			else:
				iX = -1
				iY = -1
		return (bValid, iX, iY)
 
Hi!

I'm getting a repeatable crash on hitting "End Turn". Downloaded the latest version of the mod and the patch today. Running a Huge game as the Red Syndicate.

Save file attached. Python logs don't seem to show anything useful - crash is in civgamecore.dll

Thanks!
 

Attachments

Hi!

I'm getting a repeatable crash on hitting "End Turn". Downloaded the latest version of the mod and the patch today. Running a Huge game as the Red Syndicate.

Save file attached. Python logs don't seem to show anything useful - crash is in civgamecore.dll

Thanks!

This is the "black hole too close to the edge of the map" bug. It will be fixed in the next version.

In your game there is a black hole near the upper edge of the map not too far from the center of that edge. It is 4 spaces from the edge. Sadly, that is 1 space too close. Having a ship enter a grav field that is 2 spaces from the edge of a map causes the search for the associated black hole to try to look at plots that are off the map and therefore do not actually exist, causing it to crash. If you delete that black hole in Worldbuilder, you can continue to play the save.

The issue only happens for maps that don't wrap, and only if it randomly puts a black hole too close to the edge. It doesn't happen most of the time. It doesn't happen at all if you use maps that wrap (the only one that does is the regular Final Frontier map).
 
This is the "black hole too close to the edge of the map" bug. It will be fixed in the next version.

In your game there is a black hole near the upper edge of the map not too far from the center of that edge. It is 4 spaces from the edge. Sadly, that is 1 space too close. Having a ship enter a grav field that is 2 spaces from the edge of a map causes the search for the associated black hole to try to look at plots that are off the map and therefore do not actually exist, causing it to crash. If you delete that black hole in Worldbuilder, you can continue to play the save.

The issue only happens for maps that don't wrap, and only if it randomly puts a black hole too close to the edge. It doesn't happen most of the time. It doesn't happen at all if you use maps that wrap (the only one that does is the regular Final Frontier map).

Thanks for the explanation - I'll do just that.
 
Back
Top Bottom