Naval Mines

Files have to be merged even if your mod component is python. Or did you only touch files that no other mod is using?
And if I have to choose between merging c++ and merging python, I'd take c++ every time, without hesitation. (But then again I'm not even slightly interested in something that the AI can probably never really understand, so I my opinion is not significant here)

Mod components only really spread when they become part of big mods, and for that purpose, SDK should be at least as good as python. Most likely a lot better though. Basically, what Afforess said.
 
Looks familiar to me... It's setting the maximum distance away from the capital that it will build a starbase. It is just using the max() function which returns the larger of the two numbers. It insures that iMaxRange is at least 60, which is actually pretty far (too far, really). The preceding line of code (in the "if" block) is getting the path distance between the capital and the plot in question, which will be checked against this iMaxRange.

The Huge size FF map is 128x80 and a Large map is 104x64 so the only map that doesn't get a 60 for this value is the Huge, which gets a 64. Since the FF map wraps in both directions, setting this to 60 (or 64 for Huge) means that it can build them almost anywhere on the map except perhaps a few plots that are the farthest away and are relatively hard to get to since it uses the path that a ship can actually travel, so it has to go around nebulas. On many, or possibly almost all, maps smaller than Huge it is likely to be able to build them anywhere on the map since the allowed distance is more than half the longer edge of the map. I've always wondered why such a large minimum value was chosen since it is apparently supposed to restrict the search for starbase locations to some region smaller than the whole map (but generally doesn't). I've wondered if this was supposed to be using the min() function, so that it would never be larger than 60 rather than never smaller than 60.
 
Looks familiar to me... It's setting the maximum distance away from the capital that it will build a starbase. It is just using the max() function which returns the larger of the two numbers. It insures that iMaxRange is at least 60, which is actually pretty far (too far, really). The preceding line of code (in the "if" block) is getting the path distance between the capital and the plot in question, which will be checked against this iMaxRange.

The Huge size FF map is 128x80 and a Large map is 104x64 so the only map that doesn't get a 60 for this value is the Huge, which gets a 64. Since the FF map wraps in both directions, setting this to 60 (or 64 for Huge) means that it can build them almost anywhere on the map except perhaps a few plots that are the farthest away and are relatively hard to get to since it uses the path that a ship can actually travel, so it has to go around nebulas. On many, or possibly almost all, maps smaller than Huge it is likely to be able to build them anywhere on the map since the allowed distance is more than half the longer edge of the map. I've always wondered why such a large minimum value was chosen since it is apparently supposed to restrict the search for starbase locations to some region smaller than the whole map (but generally doesn't). I've wondered if this was supposed to be using the min() function, so that it would never be larger than 60 rather than never smaller than 60.

Thanks. I ran into another problem. I managed to prove the world was round and all of my naval units received a +1 Movement bonus. That's not good for armed mines, which are supposed to have 0 movement points. Is there a python command to change the movement points for a specified pUnit?
 
Can't you make their DomainType be Immobile instead of Sea? Since you're placing them on the map via code, you shouldn't be restricted by their domain.
 
I have a function to determine the best plot to send a mine. However, I have a problem with determining whether or not the plot being checked is unowned (Location for needed line is marked in Red.

Question: How can I add a line to insure I only get plots that are unowned? i.e. no player owns the plot.

Spoiler :

Code:
def getBestUnownedPlot(Plot, iOwner):
	# Returns the best plot to send a mine.
	FoundBestPlot = False
	iCount = 0
	iMinRange = 2
	iMaxRange = 6
	
	for iPlotLoop in range(CyMap().numPlots()):
		pLoopPlot = CyMap().plotByIndex(iPlotLoop)
		iDistanceFrom_pCity = CyMap().calculatePathDistance(Plot, pLoopPlot)
		pPlayer = gc.getPlayer(iOwner)
		
		if pLoopPlot != Plot:
			if not pLoopPlot.isCity():
				if Plot.getOwner() == iOwner:
					[B][COLOR="Red"]Here[/COLOR][/B]
					if not hasFriendlyMine(pLoopPlot, pPlayer):
						if iDistanceFrom_pCity > iMinRange and iDistanceFrom_pCity < iMaxRange:
							Rating = getPlotRating(pLoopPlot)
							if iCount < Rating:
								iCount = Rating
								FoundBestPlot = True
								BestPlot = pLoopPlot
	
	if FoundBestPlot:
		#CyInterface().addImmediateMessage(str(iCount), "")
		return BestPlot
	else:
		return 0
 
The line immediately before the "Here" is already checking the owner of the plot. If you want to check for "no owner" then the check is "Plot.getOwner() == -1" since "-1" = NO_PLAYER in the SDK.

Edit: it is better to come in 2nd than not at all.
 
This:
if (Plot.getOwner() == -1):

I pasted your line in and replaced this line:

Code:
if Plot.getOwner() == iOwner:

The result is the line is false and never advances beyond that line. :dunno:

It should be True.

Is there another way to get where I want to go?

Edit: I figured it out. Dumb mistake. I was checking the wrong plot. It should have been checking the loopPlot. Here is the line that works:

Code:
if (pLoopPlot.getOwner() == -1):


Thanks,

Orion Veteran :cool:
 
Can you post the latest code and explain briefly what it is supposed to do?
 
Can you post the latest code and explain briefly what it is supposed to do?

Yes, when each function has tested OK, I will post all of them. For now, this is a summary what they are supposed to do.


1. def getPlotRangeForCLosestCity(Plot): This looks for and returns the AI's closest city from the plot specified, which in this case is always another city. It has min and max range variables and will be used when no unowned plots exist within range of the plot city. Another function will send the mine to the city specified by the result.

2. getBestUnownedPlot(Plot, iOwner): This function, looks for and returns the best unowned plot within a specified range to place a mine. The loop function rates each plot and returns the plot that has the highest rating. See next function.

3. def getPlotRating(pPlot): This function examines and returns a rating number for the plot specified.

4. def hasBonusOnPlot(pPlot): This function determines whether or not the specified plot has a bonus. It is used as one of the many variables that rate a plot.

Yet to be developed: A function to send the mine to the highest rated plot. I have example code in another mod to help me make this function. Another function will insure the closest city (See number 1) is moving away from the capital city. Goal is to move the mine towards the AI border cities.

So there you go.


Orion Veteran :cool:
 
And how exactly does that rating work?

Gee! Arn't we are like kids that can't wait to open presents at Christmas? I won't make you beg. :lol:

This is what the code looks like so far:

Spoiler :

Code:
def getPlotRating(pPlot):

	iPlotRating = 0
	if pPlot.getPlotType() == PlotTypes.NO_PLOT or pPlot.getPlotType() == PlotTypes.PLOT_PEAK:
		iPlotRating = iPlotRating + 0
		
	if pPlot.getPlotType() == PlotTypes.PLOT_LAND:		
		iPlotRating = iPlotRating + 1
		
	if pPlot.getPlotType() == PlotTypes.PLOT_HILLS:
		iPlotRating = iPlotRating + 3	
		
	if pPlot.getPlotType() == PlotTypes.PLOT_OCEAN:		
		iPlotRating = iPlotRating + 1
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_GRASS')):
		iPlotRating = iPlotRating + 3
			
	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS')): 
		iPlotRating = iPlotRating + 3
			
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_DESERT")):
		iPlotRating = iPlotRating + 2
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_TUNDRA')):
		iPlotRating = iPlotRating + 2
			
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_SNOW")):
		iPlotRating = iPlotRating + 1
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_ICE")):
		iPlotRating = iPlotRating + 0
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_PEAK")):
		iPlotRating = iPlotRating + 0
	
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_HILL")):
		iPlotRating = iPlotRating + 4
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_COAST")):
		iPlotRating = iPlotRating + 2
		
	if (pPlot.getTerrainType() == gc.getInfoTypeForString("TERRAIN_OCEAN")):	
		iPlotRating = iPlotRating + 1	
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_FOREST")):
		iPlotRating = iPlotRating + 4
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_JUNGLE")):
		iPlotRating = iPlotRating + 3
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_ICE")):
		iPlotRating = iPlotRating + 0
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_OASIS")):
		iPlotRating = iPlotRating + 2
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_FLOOD_PLAINS")):
		iPlotRating = iPlotRating + 1
		
	if (pPlot.getFeatureType() == gc.getInfoTypeForString("FEATURE_FALLOUT")):
		iPlotRating = iPlotRating + 0
	
	if hasBonusOnPlot(pPlot):
		iPlotRating = iPlotRating + 1
			
	return iPlotRating


Any ideas for improvement are welcomed.


Orion Veteran :cool:
 
I've got a few minor tips:

  • Store the results of those calls to CyPlot functions so you only incur the Python->C++ translation once per function.
  • You can use the in operator to make your if() tests easier to read.
  • Use += to make x = x + y easier to read. No effect on performance.
  • Define constants to getInfoTypeForString() once instead of each time.
  • Don't add 0. Use "pass" and add a comment.
Code:
[B]TERRAIN_GRASS = gc.getInfoTypeForString('TERRAIN_GRASS')[/B]

def getPlotRating(pPlot):
	[B]ePlotType = pPlot.getPlotType()[/B]
	if [B]ePlotType in[/B] [B]([/B]PlotTypes.NO_PLOT[B],[/B] PlotTypes.PLOT_PEAK[B])[/B]:
		[B]pass[/B]
	
	if [B]ePlotType[/B] == PlotTypes.PLOT_LAND:
		iPlotRating [B]+=[/B] 1

	...

	[B]eTerrainType[/B] = pPlot.getTerrainType()
	if [B]eTerrainType[/B] == [B]TERRAIN_GRASS[/B]:
		iPlotRating [B]+=[/B] 3

You can speed up all those checks by using a dictionary. This is a little more complex but still in the realm of basic Python coding.

Code:
... type ...

# set up plot terrain values
PLOT_TERRAIN_VALUE = {}
PLOT_TERRAIN_VALUE[gc.getInfoTypeForString("TERRAIN_GRASS")] = 3
PLOT_TERRAIN_VALUE[gc.getInfoTypeForString("TERRAIN_DESERT")] = 2

... feature ...

def getPlotRating(pPlot):
	ePlotType = pPlot.getPlotType()
	if ePlotType in PLOT_TYPE_VALUE:
		iPlotRating += PLOT_TYPE_VALUE[ePlotType]
	
	eTerrainType = pPlot.getTerrainType()
	if eTerrainType in PLOT_TERRAIN_VALUE:
		iPlotRating += PLOT_TERRAIN_VALUE[eTerrainType]
	
	eFeatureType = pPlot.getFeatureType()
	if eFeatureType in PLOT_FEATURE_VALUE:
		iPlotRating += PLOT_FEATURE_VALUE[eFeatureType]
	
	if hasBonusOnPlot(pPlot):
		iPlotRating += 1  # maybe have different values for different bonuses?
	
	return iPlotRating
 
How about like this?

Spoiler :

Code:
def getPlotRating(pPlot):
	iPlotRating = 0
	ePlotType = pPlot.getPlotType()
	eTerrainType = pPlot.getTerrainType()					
	eFeatureType = pPlot.getFeatureType()
		
	dPlotTypeData = {		
		PlotTypes.PLOT_HILLS: 3,
		PlotTypes.PLOT_LAND: 1,		
		PlotTypes.PLOT_OCEAN: 1
	}
			
	dTerrainData = {		
		"TERRAIN_HILL": 4,
		"TERRAIN_GRASS": 3,
		"TERRAIN_PLAINS": 3,
		"TERRAIN_DESERT": 2,
		"TERRAIN_TUNDRA": 2,
		"TERRAIN_COAST": 2,
		"TERRAIN_SNOW": 1,
		"TERRAIN_OCEAN": 1
	}
			
	dFeatureData = {		
		"FEATURE_FOREST": 4,
		"FEATURE_JUNGLE": 3,
		"FEATURE_OASIS": 2,
		"FEATURE_FLOOD_PLAINS": 1
	}
		
	for szPlotType, iPlotTypeValue in dPlotTypeData.iteritems():
		MyPlotType = str(dPlotTypeData[szPlotType])
		iPlotType = gc.getInfoTypeForString(MyPlotType)		
		if iPlotType == ePlotType:
			iPlotRating += iPlotTypeValue
	
	for szTerrainType, iTerrainValue in dTerrainData.iteritems():
		MyTerrainType = str(dTerrainData[szTerrainType])
		iTerrainType = gc.getInfoTypeForString(MyTerrainType)
		if iTerrainType == eTerrainType:
			iPlotRating += iTerrainValue
		
	for szFeatureType, iFeatureValue in dFeatureData.iteritems():
		MyFeatureType = str(dFeatureData[szFeatureType])
		iFeatureType = gc.getInfoTypeForString(MyFeatureType)
		if iFeatureType == eFeatureType:
			iPlotRating += iFeatureValue
	
	if hasBonusOnPlot(pPlot):
		iPlotRating += 1  # maybe have different values for different bonuses?
	
	return iPlotRating
 
I could use a few ideas on how to improve my strategy for determining the next city to send a mine. Currently, I have a function that determines the closest city to a specified plot city. The code has a check to make sure the city found has a greater plot distance to the Capital city than it has from the specified plot city. Reason, I want the AI to place mines around all of the border cities. My difficulty is determining the next border city to send the mine to when the closest city is equal to the distance from the Capital city. There could be several border cities with the same plot distance from the capital city. I certainly don't want to repeat sending mines to a city I have previously sent mines to. Any ideas on how I might determine the next city to go to?
 
Well, you will need to remember how many mines have been placed around each city, but then, as the number of mines increases, make the value (or chance) of the AI placing mines near that city decrease.
 
Well, you will need to remember how many mines have been placed around each city, but then, as the number of mines increases, make the value (or chance) of the AI placing mines near that city decrease.

I think I can write a function to do just that.

Thanks.

Orion Veteran :cool:
 
Back
Top Bottom