public static void GenMapPoints(CommandEventArgs e) { try { e.Mobile.SendMessage("Begin generation."); Dolphin fish = new Dolphin(); SeaChart tempMap = null; double maxd = 0; double mind = 64; int count = 0; int failedPin = 0; int pinNdx = 0; int pinCollisions = 0; int notInRect = 0; int specialExclusions = 0; int badMap = 0; int wetTileFailure = 0; int badMapBounds = 0; int failMap = 0; int noLand = 0; int minDist = 0; SortedList <double, MapNode> list = new SortedList <double, MapNode>(); for (int ji = 0; ji < Utility.BritWrap.Length; ji++) { for (int mx = Utility.BritWrap[ji].Start.X; mx <= (Utility.BritWrap[ji].Start.X + Utility.BritWrap[ji].Width - 1); mx++) { for (int my = Utility.BritWrap[ji].Start.Y; my <= (Utility.BritWrap[ji].Start.Y + Utility.BritWrap[ji].Height - 1); my++) { // are we inside the brit rect? if (Utility.BritWrap[ji].Contains(new Point2D(mx, my)) == false) { // bad point - not in rect notInRect++; continue; } // wet tile rect sanity check - make sure we are surrounded by water (not a puddle) if (PuddleCheck(Utility.BritWrap[ji], new Point2D(mx, my)) == false) { wetTileFailure++; continue; } // exclude special areas (eg. angel island prison, dungeons) if (ValidRegion(mx, my) == false) { specialExclusions++; continue; } // okay, we have what looks like a good map center and first pin // we must have land within 64 tiles Point3D wetLoc = new Point3D(mx, my, Map.Felucca.GetAverageZ(mx, my)); Point3D dryLoc = Spawner.GetSpawnPosition(Map.Felucca, wetLoc, 64, false, null); if (wetLoc == dryLoc) { // spawner failed to find a good location noLand++; continue; } // okay, we have a focus point // now place the remaing N pins with validation // dist2land to old point double dist2land = GetDistance(new Point2D(wetLoc), new Point2D(dryLoc)); // level of this map int level = (dist2land < 21) ? 1 : (dist2land < 31) ? 2 : (dist2land < 41) ? 3 : (dist2land < 51) ? 4 : (dist2land < 91) ? 5 : 0; // create a temp map to validate pin locations #region TEMP MAP CREATION & VALIDATION if (tempMap != null) { tempMap.Delete(); tempMap = null; } // new level-sized map tempMap = new SeaChart(level, new Point2D(wetLoc)); // make sure there is no w/h failure. I think this happens when we are at the map edge if (tempMap.Bounds.Width <= 0 || tempMap.Height <= 0) { badMap++; continue; } // even though our wet-point is in the brit rect, the bounds may not be. Exclude those maps here if (!Utility.BritWrap[ji].Contains(tempMap.Bounds.Start) || !Utility.BritWrap[ji].Contains(tempMap.Bounds.End)) { badMapBounds++; continue; } #endregion TEMP MAP CREATION & VALIDATION #region ADD PINS // okay, place the start pin Point2D[] pins = new Point2D[6]; pinNdx = 0; pins[pinNdx++] = new Point2D(wetLoc.X, wetLoc.Y); Point3D newPinLoc; // new pin location Point3D lastPinLoc = wetLoc; // last pin location // okay, try to place 6 pins int good = 1; // how many pins have we placed? for (int hx = 1; hx < 6; hx++) // 6 pins { // 100 tries to place a pin for (int retry = 0; retry < 100; retry++) { // get a new pin location newPinLoc = Spawner.GetSpawnPosition(Map.Felucca, lastPinLoc, 200, false, false, Spawner.SpawnFlags.SpawnFar, fish); if (newPinLoc == lastPinLoc) { continue; } // did we exit the brit rect? if (Utility.BritWrap[ji].Contains(newPinLoc) == false) { // bad point - not in rect notInRect++; continue; } // wet tile rect sanity check - make sure we are surrounded by water (not a puddle) if (PuddleCheck(Utility.BritWrap[ji], new Point2D(newPinLoc)) == false) { wetTileFailure++; continue; } // is this pin in an illegal region? if (ValidRegion(newPinLoc.X, newPinLoc.Y) == false) { specialExclusions++; continue; } // validate that we don't exceed the map bounds if (ValidBounds(tempMap, newPinLoc.X, newPinLoc.Y) == false) { badMap++; continue; } // validate a minmum distance if (ValidDistance(150, new Point2D(lastPinLoc), new Point2D(newPinLoc)) == false) { minDist++; continue; } if (ValidUnique(pins, pinNdx, new Point2D(newPinLoc.X, newPinLoc.Y)) == false) { pinCollisions++; continue; } // okay, looks to be a reasonable pin location pins[pinNdx++] = new Point2D(newPinLoc.X, newPinLoc.Y); lastPinLoc = newPinLoc; // make the next pin relative to this pin good++; break; } } if (good < 6) { // skip this location as we can't place sufficient pins failedPin++; continue; } #endregion ADD PINS // Create an actual map and run sanity checks on it. // for some unknown reason, we're still getting like 10% bad maps #region FINAL CHECK for (int rm = 0; rm < pins.Length; rm++) { tempMap.AddWorldPin(pins[rm].X, pins[rm].Y); } bool[] failTest = new bool[10]; if (CheckMap(tempMap, failTest) == false) { failMap++; tempMap.ClearPins(); continue; } tempMap.ClearPins(); #endregion FINAL CHECK // maps processed count++; // give a little feedback since thie process is so slow if (count % 1000 == 0) { Console.Write("{0},", count); } // add to sorted list double key = Utility.RandomDouble(); bool retrykey = false; while (list.ContainsKey(key)) { // feedback for key retries Console.Write("."); key = Utility.RandomDouble(); retrykey = true; } list.Add(key, new MapNode(level, pins)); if (retrykey == true) { Console.Write(","); } } } } // no longer need our test fish fish.Delete(); Console.WriteLine(); Console.WriteLine("Fill arrays"); int[] indexes = new int[m_Locations.GetUpperBound(0) + 1]; // column index foreach (KeyValuePair <double, MapNode> kvp in list) { // only store the first 500 (m_Locations.GetUpperBound(1)+1) for each level if (indexes[kvp.Value.Level - 1] > m_Locations.GetUpperBound(1)) { continue; } m_Locations[kvp.Value.Level - 1, indexes[kvp.Value.Level - 1]] = new Point2D[6] { kvp.Value.Pins[0], kvp.Value.Pins[1], kvp.Value.Pins[2], kvp.Value.Pins[3], kvp.Value.Pins[4], kvp.Value.Pins[5] }; indexes[kvp.Value.Level - 1]++; } Console.WriteLine("Write the data"); try { int rowx, coly; string filePath = Path.Combine(Core.BaseDirectory, "Data/seatreasure.bin"); using (Stream stream = File.Open(filePath, FileMode.Create)) { BinaryFormatter bin = new BinaryFormatter(); for (rowx = 0; rowx <= m_Locations.GetUpperBound(0); rowx++) { for (coly = 0; coly <= m_Locations.GetUpperBound(1); coly++) { bin.Serialize(stream, m_Locations[rowx, coly]); } } } // read it back using (Stream stream = File.Open(filePath, FileMode.Open)) { BinaryFormatter bin = new BinaryFormatter(); for (rowx = 0; rowx <= m_Locations.GetUpperBound(0); rowx++) { for (coly = 0; coly <= m_Locations.GetUpperBound(1); coly++) { m_Locations[rowx, coly] = new Point2D[6]; m_Locations[rowx, coly] = (Point2D[])bin.Deserialize(stream); } } } } catch (Exception ex) { LogHelper.LogException(ex); } e.Mobile.SendMessage("Generation complete with {0} maps processed.", count); e.Mobile.SendMessage("{0} map locations were skipped for bad pin placement.", failedPin); e.Mobile.SendMessage("{0} pin locations were skipped because of pin collisions.", pinCollisions); e.Mobile.SendMessage("{0} points were skipped: outside rect.", notInRect); e.Mobile.SendMessage("{0} points were skipped: special area.", specialExclusions); e.Mobile.SendMessage("{0} maps were skipped: bad width/height.", badMap); e.Mobile.SendMessage("{0} pins were skipped: not wet.", wetTileFailure); e.Mobile.SendMessage("{0} pins were skipped: min distance.", minDist); e.Mobile.SendMessage("{0} maps were skipped: bad map bounds.", badMapBounds); e.Mobile.SendMessage("{0} maps were skipped: failed map test.", failMap); e.Mobile.SendMessage("{0} maps were skipped: failed dist to land test.", noLand); e.Mobile.SendMessage("{0} total maps output.", count - failedPin); } catch (Exception ex) { LogHelper.LogException(ex); } }