示例#1
0
 public Float3 GetNearestMetalSpot(Float3 mypos)
 {
     if (!isMetalMap)
     {
         double    closestdistancesquared = 1000000000000;
         Float3    bestpos  = null;
         MetalSpot bestspot = null;
         foreach (MetalSpot metalspot in MetalSpots)
         {
             if (!MetalSpotsUsed.Contains(metalspot))
             {
                 if (bestpos == null)
                 {
                     bestpos = metalspot.Pos;
                 }
                 double thisdistancesquared = Float3Helper.GetSquaredDistance(mypos, metalspot.Pos);
                 //logfile.WriteLine( "thisdistancesquared = " + thisdistancesquared + " closestdistancesquared= " + closestdistancesquared );
                 if (thisdistancesquared < closestdistancesquared)
                 {
                     closestdistancesquared = thisdistancesquared;
                     bestpos  = metalspot.Pos;
                     bestspot = metalspot;
                 }
             }
         }
         return(bestspot.Pos);
     }
     else
     {
         return(mypos); // if metal map just return passed-in pos
     }
 }
示例#2
0
 void ReserveMetalExtractorSpaces()
 {
     foreach (object metalspotobject in MetalSpots)
     {
         MetalSpot metalspot = metalspotobject as MetalSpot;
         logfile.WriteLine("reserving space for " + metalspot.Pos.ToString());
         BuildMap.GetInstance().ReserveSpace(this, (int)(metalspot.Pos.x / 8), (int)(metalspot.Pos.z / 8), 6, 6);
     }
 }
示例#3
0
        // loads cache file
        // returns true if cache loaded ok, otherwise false if not found, out-of-date, etc
        // we check the version and return false if out-of-date
        bool LoadCache()
        {
            string MapName       = aicallback.GetMapName();
            string cachefilepath = Path.Combine(csai.CacheDirectoryPath, MapName + "_metal.xml");

            if (!File.Exists(cachefilepath))
            {
                logfile.WriteLine("cache file doesnt exist -> building");
                return(false);
            }

            XmlDocument cachedom = XmlHelper.OpenDom(cachefilepath);
            XmlElement  metadata = cachedom.SelectSingleNode("/root/metadata") as XmlElement;
            string      cachemetalclassversion = metadata.GetAttribute("version");

            if (cachemetalclassversion != MetalClassVersion)
            {
                logfile.WriteLine("cache file out of date ( " + cachemetalclassversion + " vs " + MetalClassVersion + " ) -> rebuilding");
                return(false);
            }

            logfile.WriteLine(cachedom.InnerXml);

            isMetalMap = Convert.ToBoolean(metadata.GetAttribute("ismetalmap"));

            if (isMetalMap)
            {
                logfile.WriteLine("metal map");
                return(true);
            }


            XmlElement metalspots   = cachedom.SelectSingleNode("/root/metalspots") as XmlElement;
            ArrayList  metalspotsal = new ArrayList();

            foreach (XmlElement metalspot in metalspots.SelectNodes("metalspot"))
            {
                int    amount = Convert.ToInt32(metalspot.GetAttribute("amount"));
                Float3 pos    = new Float3();
                Float3Helper.WriteXmlElementToFloat3(metalspot, pos);
                //pos.LoadCsv( metalspot.GetAttribute("pos") );
                MetalSpot newmetalspot = new MetalSpot(amount, pos);
                metalspotsal.Add(newmetalspot);
                // logfile.WriteLine( "metalspot xml: " + metalspot.InnerXml );
                logfile.WriteLine("metalspot: " + newmetalspot.ToString());
            }
            MetalSpots = (MetalSpot[])metalspotsal.ToArray(typeof(MetalSpot));

            logfile.WriteLine("cache file loaded");
            return(true);
        }
示例#4
0
 // for debugging / convincing oneself spots are in right place
 void DrawMetalSpots()
 {
     if (!isMetalMap)
     {
         foreach (object metalspotobject in MetalSpots)
         {
             MetalSpot metalspot = metalspotobject as MetalSpot;
             logfile.WriteLine("drawing spot at " + metalspot.Pos);
             aicallback.DrawUnit("ARMMEX", metalspot.Pos, 0.0f, 500, aicallback.GetMyAllyTeam(), true, true);
         }
         foreach (object metalspotobject in MetalSpotsUsed)
         {
             MetalSpot metalspot = metalspotobject as MetalSpot;
             logfile.WriteLine("drawing usedspot at " + metalspot.Pos);
             aicallback.DrawUnit("ARMFORT", metalspot.Pos, 0.0f, 500, aicallback.GetMyAllyTeam(), true, true);
         }
     }
     else
     {
         aicallback.SendTextMsg("Metal analyzer reports this is a metal map", 0);
     }
 }
示例#5
0
        // algorithm more or less by krogothe
        // ported from Submarine's original C++ version
        public void SearchMetalSpots()
        {	
            logfile.WriteLine( "SearchMetalSpots() >>>");
            
            isMetalMap = false;
        
            ArrayList metalspotsal = new ArrayList();
            
            int mapheight = aicallback.GetMapHeight() / 2; //metal map has 1/2 resolution of normal map
            int mapwidth = aicallback.GetMapWidth() / 2;
            double mapmaxmetal = aicallback.GetMaxMetal();
            int totalcells = mapheight * mapwidth;
            
            logfile.WriteLine( "mapwidth: " + mapwidth + " mapheight " + mapheight + " maxmetal:" + mapmaxmetal );
            
            byte[] metalmap = aicallback.GetMetalMap(); // original metal map
            int[,] metalremaining = new int[ mapwidth, mapheight ];  // actual metal available at that point. we remove metal from this as we add spots to MetalSpots
            int[,] SpotAvailableMetal = new int [ mapwidth, mapheight ]; // amount of metal an extractor on this spot could make
            int[,] NormalizedSpotAvailableMetal = new int [ mapwidth, mapheight ]; // SpotAvailableMetal, normalized to 0-255 range
        
            int totalmetal = 0;
            ArrayIndexer arrayindexer = new ArrayIndexer( mapwidth, mapheight );
            //Load up the metal Values in each pixel
            logfile.WriteLine( "width: " + mapwidth + " height: " + mapheight );
            for (int y = 0; y < mapheight; y++)
            {
                //string logline = "";
                for( int x = 0; x < mapwidth; x++ )
                {
                    metalremaining[ x, y ] = (int)metalmap[ arrayindexer.GetIndex( x, y ) ];
                    totalmetal += metalremaining[ x, y ];		// Count the total metal so you can work out an average of the whole map
                    //logline += metalremaining[ x, y ].ToString() + " ";
                  //  logline += metalremaining[ x, y ] + " ";
                }
               // logfile.WriteLine( logline );
            }
            logfile.WriteLine ("*******************************************");
        
            double averagemetal = ((double)totalmetal) / ((double)totalcells);  //do the average
           // int maxmetal = 0;

            int ExtractorRadius = (int)( aicallback.GetExtractorRadius() / 16.0 );
            int DoubleExtractorRadius = ExtractorRadius * 2;
            int SquareExtractorRadius = ExtractorRadius * ExtractorRadius; //used to speed up loops so no recalculation needed
            int FourSquareExtractorRadius = 4 * SquareExtractorRadius; // same as above 
            double CellsInRadius = Math.PI * ExtractorRadius * ExtractorRadius;
            
            int maxmetalspotamount = 0;
            logfile.WriteLine( "Calculating available metal for each spot..." );
            SpotAvailableMetal = CalculateAvailableMetalForEachSpot( metalremaining, ExtractorRadius, out maxmetalspotamount );
            
            logfile.WriteLine( "Normalizing..." );
            // normalize the metal so any map will have values 0-255, no matter how much metal it has
            int[,] NormalizedMetalRemaining = new int[ mapwidth, mapheight ];
            for (int y = 0; y < mapheight; y++)
            {
                for (int x = 0; x < mapwidth; x++)
                {
                    NormalizedSpotAvailableMetal[ x, y ] = ( SpotAvailableMetal[ x, y ] * 255 ) / maxmetalspotamount;
                }
            }
            
            logfile.WriteLine( "maxmetalspotamount: " + maxmetalspotamount );
            
            bool Stopme = false;
            int SpotsFound = 0;
            //logfile.WriteLine( BuildTable.GetInstance().GetBiggestMexUnit().ToString() );
           // IUnitDef biggestmex = BuildTable.GetInstance().GetBiggestMexUnit();
           // logfile.WriteLine( "biggestmex is " + biggestmex.name + " " + biggestmex.humanName );
            for (int spotindex = 0; spotindex < MaxSpots && !Stopme; spotindex++)
            {	                
                logfile.WriteLine( "spotindex: " + spotindex );
                int bestspotx = 0, bestspoty = 0;
                int actualmetalatbestspot = 0; // use to try to put extractors over spot itself
                //finds the best spot on the map and gets its coords
                int BestNormalizedAvailableSpotAmount = 0;
                for (int y = 0; y < mapheight; y++)
                {
                    for (int x = 0; x < mapwidth; x++)
                    {
                        if( NormalizedSpotAvailableMetal[ x, y ] > BestNormalizedAvailableSpotAmount ||
                            ( NormalizedSpotAvailableMetal[ x, y ] == BestNormalizedAvailableSpotAmount && 
                            metalremaining[ x, y ] > actualmetalatbestspot ) )
                        {
                            BestNormalizedAvailableSpotAmount = NormalizedSpotAvailableMetal[ x, y ];
                            bestspotx = x;
                            bestspoty = y;
                            actualmetalatbestspot = metalremaining[ x, y ];
                        }
                    }
                }		
                logfile.WriteLine( "BestNormalizedAvailableSpotAmount: " + BestNormalizedAvailableSpotAmount );                
                if( BestNormalizedAvailableSpotAmount < MinMetalForSpot )
                {
                    Stopme = true; // if the spots get too crappy it will stop running the loops to speed it all up
                    logfile.WriteLine( "Remaining spots too small; stopping search" );
                }
        
                if( !Stopme )
                {
                    Float3 pos = new Float3();
                    pos.x = bestspotx * 2 * MovementMaps.SQUARE_SIZE;
                    pos.z = bestspoty * 2 * MovementMaps.SQUARE_SIZE;
                    pos.y = aicallback.GetElevation( pos.x, pos.z );
                    
                    //pos = Map.PosToFinalBuildPos( pos, biggestmex );
                
                    logfile.WriteLine( "Metal spot: " + pos + " " + BestNormalizedAvailableSpotAmount );
                    MetalSpot thismetalspot = new MetalSpot( (int)( ( BestNormalizedAvailableSpotAmount  * mapmaxmetal * maxmetalspotamount ) / 255 ), pos );
                    
                //    if (aicallback.CanBuildAt(biggestmex, pos) )
                  //  {
                       // pos = Map.PosToBuildMapPos( pos, biggestmex );
                       // logfile.WriteLine( "Metal spot: " + pos + " " + BestNormalizedAvailableSpotAmount );
                        
                   //     if(pos.z >= 2 && pos.x >= 2 && pos.x < mapwidth -2 && pos.z < mapheight -2)
                  //      {
                          //  if(CanBuildAt(pos.x, pos.z, biggestmex.xsize, biggestmex.ysize))
                           // {
                                metalspotsal.Add( thismetalspot );			
                                SpotsFound++;
        
                                //if(pos.y >= 0)
                                //{
                                   // SetBuildMap(pos.x-2, pos.z-2, biggestmex.xsize+4, biggestmex.ysize+4, 1);
                                //}
                                //else
                                //{
                                    //SetBuildMap(pos.x-2, pos.z-2, biggestmex.xsize+4, biggestmex.ysize+4, 5);
                                //}
                          //  }
                     //   }
                 //   }
                        
                    for (int myx = bestspotx - (int)ExtractorRadius; myx < bestspotx + (int)ExtractorRadius; myx++)
                    {
                        if (myx >= 0 && myx < mapwidth )
                        {
                            for (int myy = bestspoty - (int)ExtractorRadius; myy < bestspoty + (int)ExtractorRadius; myy++)
                            {
                                if ( myy >= 0 && myy < mapheight &&
                                    ( ( bestspotx - myx ) * ( bestspotx - myx ) + ( bestspoty - myy ) * ( bestspoty - myy ) ) <= (int)SquareExtractorRadius )
                                {
                                    metalremaining[ myx, myy ] = 0; //wipes the metal around the spot so its not counted twice
                                    NormalizedSpotAvailableMetal[ myx, myy ] = 0;
                                }
                            }
                        }
                    }
        
                    // Redo the whole averaging process around the picked spot so other spots can be found around it
                    for (int y = bestspoty - (int)DoubleExtractorRadius; y < bestspoty + (int)DoubleExtractorRadius; y++)
                    {
                        if(y >=0 && y < mapheight)
                        {
                            for (int x = bestspotx - (int)DoubleExtractorRadius; x < bestspotx + (int)DoubleExtractorRadius; x++)
                            {
                                //funcion below is optimized so it will only update spots between r and 2r, greatly speeding it up
                                if((bestspotx - x)*(bestspotx - x) + (bestspoty - y)*(bestspoty - y) <= (int)FourSquareExtractorRadius && 
                                    x >=0 && x < mapwidth && 
                                    NormalizedSpotAvailableMetal[ x, y ] > 0 )
                                {
                                    totalmetal = 0;
                                    for (int myx = x - (int)ExtractorRadius; myx < x + (int)ExtractorRadius; myx++)
                                    {
                                        if (myx >= 0 && myx < mapwidth )
                                        {
                                            for (int myy = y - (int)ExtractorRadius; myy < y + (int)ExtractorRadius; myy++)
                                            { 
                                                if (myy >= 0 && myy < mapheight && 
                                                    ((x - myx)*(x - myx) + (y - myy)*(y - myy)) <= (int)SquareExtractorRadius )
                                                {
                                                    totalmetal += metalremaining[ myx, myy ]; //recalculate nearby spots to account for deleted metal from chosen spot
                                                }
                                            }
                                        }
                                    }
                                    NormalizedSpotAvailableMetal[ x, y ] = totalmetal * 255 / maxmetalspotamount; //set that spots metal amount 
                                }
                            }
                        }
                    }
                }
            }
        
            if(SpotsFound > 500)
            {
                isMetalMap = true;
                metalspotsal.Clear();
                logfile.WriteLine( "Map is considered to be a metal map" );
            }
            else
            {
                isMetalMap = false;
        
                // debug
                //for(list<AAIMetalSpot>::iterator spot = metal_spots.begin(); spot != metal_spots.end(); spot++)
            }
            
            MetalSpots = ( MetalSpot[] )metalspotsal.ToArray( typeof( MetalSpot ) );
            
            SaveCache();
            logfile.WriteLine( "SearchMetalSpots() <<<");
        }
示例#6
0
 // loads cache file
 // returns true if cache loaded ok, otherwise false if not found, out-of-date, etc
 // we check the version and return false if out-of-date
 bool LoadCache()
 {
     string MapName = aicallback.GetMapName();
     string cachefilepath = Path.Combine( csai.CacheDirectoryPath, MapName + "_metal.xml" );
     
     if( !File.Exists( cachefilepath ) )
     {
         logfile.WriteLine( "cache file doesnt exist -> building" );
         return false;
     }
     
     XmlDocument cachedom = XmlHelper.OpenDom( cachefilepath );
     XmlElement metadata = cachedom.SelectSingleNode( "/root/metadata" ) as XmlElement;
     string cachemetalclassversion = metadata.GetAttribute( "version" );
     if( cachemetalclassversion != MetalClassVersion )
     {
         logfile.WriteLine( "cache file out of date ( " + cachemetalclassversion + " vs " + MetalClassVersion + " ) -> rebuilding" );
         return false;
     }
     
     logfile.WriteLine( cachedom.InnerXml );
     
     isMetalMap = Convert.ToBoolean( metadata.GetAttribute( "ismetalmap" ) );
     
     if( isMetalMap )
     {
         logfile.WriteLine( "metal map" );
         return true;
     }
     
     
     XmlElement metalspots = cachedom.SelectSingleNode( "/root/metalspots" ) as XmlElement;
     ArrayList metalspotsal = new ArrayList();
     foreach( XmlElement metalspot in metalspots.SelectNodes( "metalspot" ) )
     {
         int amount = Convert.ToInt32( metalspot.GetAttribute("amount") );
         Float3 pos = new Float3();
         Float3Helper.WriteXmlElementToFloat3( metalspot, pos );
         //pos.LoadCsv( metalspot.GetAttribute("pos") );
         MetalSpot newmetalspot = new MetalSpot( amount, pos );
         metalspotsal.Add( newmetalspot );
         // logfile.WriteLine( "metalspot xml: " + metalspot.InnerXml );
         logfile.WriteLine( "metalspot: " + newmetalspot.ToString() );
     }
     MetalSpots = (MetalSpot[])metalspotsal.ToArray( typeof( MetalSpot ) );
     
     logfile.WriteLine( "cache file loaded" );
     return true;
 }
示例#7
0
        // algorithm more or less by krogothe
        // ported from Submarine's original C++ version
        public void SearchMetalSpots()
        {
            logfile.WriteLine("SearchMetalSpots() >>>");

            isMetalMap = false;

            ArrayList metalspotsal = new ArrayList();

            int    mapheight   = aicallback.GetMapHeight() / 2; //metal map has 1/2 resolution of normal map
            int    mapwidth    = aicallback.GetMapWidth() / 2;
            double mapmaxmetal = aicallback.GetMaxMetal();
            int    totalcells  = mapheight * mapwidth;

            logfile.WriteLine("mapwidth: " + mapwidth + " mapheight " + mapheight + " maxmetal:" + mapmaxmetal);

            byte[] metalmap = aicallback.GetMetalMap();                          // original metal map
            int[,] metalremaining               = new int[mapwidth, mapheight];  // actual metal available at that point. we remove metal from this as we add spots to MetalSpots
            int[,] SpotAvailableMetal           = new int [mapwidth, mapheight]; // amount of metal an extractor on this spot could make
            int[,] NormalizedSpotAvailableMetal = new int [mapwidth, mapheight]; // SpotAvailableMetal, normalized to 0-255 range

            int          totalmetal   = 0;
            ArrayIndexer arrayindexer = new ArrayIndexer(mapwidth, mapheight);

            //Load up the metal Values in each pixel
            logfile.WriteLine("width: " + mapwidth + " height: " + mapheight);
            for (int y = 0; y < mapheight; y++)
            {
                //string logline = "";
                for (int x = 0; x < mapwidth; x++)
                {
                    metalremaining[x, y] = (int)metalmap[arrayindexer.GetIndex(x, y)];
                    totalmetal          += metalremaining[x, y];        // Count the total metal so you can work out an average of the whole map
                    //logline += metalremaining[ x, y ].ToString() + " ";
                    //  logline += metalremaining[ x, y ] + " ";
                }
                // logfile.WriteLine( logline );
            }
            logfile.WriteLine("*******************************************");

            double averagemetal = ((double)totalmetal) / ((double)totalcells);  //do the average
            // int maxmetal = 0;

            int    ExtractorRadius           = (int)(aicallback.GetExtractorRadius() / 16.0);
            int    DoubleExtractorRadius     = ExtractorRadius * 2;
            int    SquareExtractorRadius     = ExtractorRadius * ExtractorRadius; //used to speed up loops so no recalculation needed
            int    FourSquareExtractorRadius = 4 * SquareExtractorRadius;         // same as above
            double CellsInRadius             = Math.PI * ExtractorRadius * ExtractorRadius;

            int maxmetalspotamount = 0;

            logfile.WriteLine("Calculating available metal for each spot...");
            SpotAvailableMetal = CalculateAvailableMetalForEachSpot(metalremaining, ExtractorRadius, out maxmetalspotamount);

            logfile.WriteLine("Normalizing...");
            // normalize the metal so any map will have values 0-255, no matter how much metal it has
            int[,] NormalizedMetalRemaining = new int[mapwidth, mapheight];
            for (int y = 0; y < mapheight; y++)
            {
                for (int x = 0; x < mapwidth; x++)
                {
                    NormalizedSpotAvailableMetal[x, y] = (SpotAvailableMetal[x, y] * 255) / maxmetalspotamount;
                }
            }

            logfile.WriteLine("maxmetalspotamount: " + maxmetalspotamount);

            bool Stopme     = false;
            int  SpotsFound = 0;

            //logfile.WriteLine( BuildTable.GetInstance().GetBiggestMexUnit().ToString() );
            // IUnitDef biggestmex = BuildTable.GetInstance().GetBiggestMexUnit();
            // logfile.WriteLine( "biggestmex is " + biggestmex.name + " " + biggestmex.humanName );
            for (int spotindex = 0; spotindex < MaxSpots && !Stopme; spotindex++)
            {
                logfile.WriteLine("spotindex: " + spotindex);
                int bestspotx = 0, bestspoty = 0;
                int actualmetalatbestspot = 0; // use to try to put extractors over spot itself
                //finds the best spot on the map and gets its coords
                int BestNormalizedAvailableSpotAmount = 0;
                for (int y = 0; y < mapheight; y++)
                {
                    for (int x = 0; x < mapwidth; x++)
                    {
                        if (NormalizedSpotAvailableMetal[x, y] > BestNormalizedAvailableSpotAmount ||
                            (NormalizedSpotAvailableMetal[x, y] == BestNormalizedAvailableSpotAmount &&
                             metalremaining[x, y] > actualmetalatbestspot))
                        {
                            BestNormalizedAvailableSpotAmount = NormalizedSpotAvailableMetal[x, y];
                            bestspotx             = x;
                            bestspoty             = y;
                            actualmetalatbestspot = metalremaining[x, y];
                        }
                    }
                }
                logfile.WriteLine("BestNormalizedAvailableSpotAmount: " + BestNormalizedAvailableSpotAmount);
                if (BestNormalizedAvailableSpotAmount < MinMetalForSpot)
                {
                    Stopme = true; // if the spots get too crappy it will stop running the loops to speed it all up
                    logfile.WriteLine("Remaining spots too small; stopping search");
                }

                if (!Stopme)
                {
                    Float3 pos = new Float3();
                    pos.x = bestspotx * 2 * MovementMaps.SQUARE_SIZE;
                    pos.z = bestspoty * 2 * MovementMaps.SQUARE_SIZE;
                    pos.y = aicallback.GetElevation(pos.x, pos.z);

                    //pos = Map.PosToFinalBuildPos( pos, biggestmex );

                    logfile.WriteLine("Metal spot: " + pos + " " + BestNormalizedAvailableSpotAmount);
                    MetalSpot thismetalspot = new MetalSpot((int)((BestNormalizedAvailableSpotAmount * mapmaxmetal * maxmetalspotamount) / 255), pos);

                    //    if (aicallback.CanBuildAt(biggestmex, pos) )
                    //  {
                    // pos = Map.PosToBuildMapPos( pos, biggestmex );
                    // logfile.WriteLine( "Metal spot: " + pos + " " + BestNormalizedAvailableSpotAmount );

                    //     if(pos.z >= 2 && pos.x >= 2 && pos.x < mapwidth -2 && pos.z < mapheight -2)
                    //      {
                    //  if(CanBuildAt(pos.x, pos.z, biggestmex.xsize, biggestmex.ysize))
                    // {
                    metalspotsal.Add(thismetalspot);
                    SpotsFound++;

                    //if(pos.y >= 0)
                    //{
                    // SetBuildMap(pos.x-2, pos.z-2, biggestmex.xsize+4, biggestmex.ysize+4, 1);
                    //}
                    //else
                    //{
                    //SetBuildMap(pos.x-2, pos.z-2, biggestmex.xsize+4, biggestmex.ysize+4, 5);
                    //}
                    //  }
                    //   }
                    //   }

                    for (int myx = bestspotx - (int)ExtractorRadius; myx < bestspotx + (int)ExtractorRadius; myx++)
                    {
                        if (myx >= 0 && myx < mapwidth)
                        {
                            for (int myy = bestspoty - (int)ExtractorRadius; myy < bestspoty + (int)ExtractorRadius; myy++)
                            {
                                if (myy >= 0 && myy < mapheight &&
                                    ((bestspotx - myx) * (bestspotx - myx) + (bestspoty - myy) * (bestspoty - myy)) <= (int)SquareExtractorRadius)
                                {
                                    metalremaining[myx, myy] = 0;   //wipes the metal around the spot so its not counted twice
                                    NormalizedSpotAvailableMetal[myx, myy] = 0;
                                }
                            }
                        }
                    }

                    // Redo the whole averaging process around the picked spot so other spots can be found around it
                    for (int y = bestspoty - (int)DoubleExtractorRadius; y < bestspoty + (int)DoubleExtractorRadius; y++)
                    {
                        if (y >= 0 && y < mapheight)
                        {
                            for (int x = bestspotx - (int)DoubleExtractorRadius; x < bestspotx + (int)DoubleExtractorRadius; x++)
                            {
                                //funcion below is optimized so it will only update spots between r and 2r, greatly speeding it up
                                if ((bestspotx - x) * (bestspotx - x) + (bestspoty - y) * (bestspoty - y) <= (int)FourSquareExtractorRadius &&
                                    x >= 0 && x < mapwidth &&
                                    NormalizedSpotAvailableMetal[x, y] > 0)
                                {
                                    totalmetal = 0;
                                    for (int myx = x - (int)ExtractorRadius; myx < x + (int)ExtractorRadius; myx++)
                                    {
                                        if (myx >= 0 && myx < mapwidth)
                                        {
                                            for (int myy = y - (int)ExtractorRadius; myy < y + (int)ExtractorRadius; myy++)
                                            {
                                                if (myy >= 0 && myy < mapheight &&
                                                    ((x - myx) * (x - myx) + (y - myy) * (y - myy)) <= (int)SquareExtractorRadius)
                                                {
                                                    totalmetal += metalremaining[myx, myy];   //recalculate nearby spots to account for deleted metal from chosen spot
                                                }
                                            }
                                        }
                                    }
                                    NormalizedSpotAvailableMetal[x, y] = totalmetal * 255 / maxmetalspotamount;   //set that spots metal amount
                                }
                            }
                        }
                    }
                }
            }

            if (SpotsFound > 500)
            {
                isMetalMap = true;
                metalspotsal.Clear();
                logfile.WriteLine("Map is considered to be a metal map");
            }
            else
            {
                isMetalMap = false;

                // debug
                //for(list<AAIMetalSpot>::iterator spot = metal_spots.begin(); spot != metal_spots.end(); spot++)
            }

            MetalSpots = ( MetalSpot[] )metalspotsal.ToArray(typeof(MetalSpot));

            SaveCache();
            logfile.WriteLine("SearchMetalSpots() <<<");
        }