/// <summary> /// Makes a point which is in the closest entry region to the group of pirates, /// TODO: but not in the same entry region as any of them. /// </summary> /// <param name="pirates">The move events representing pirates</param> /// <param name="entryRegions">All entry regions</param> /// <returns>A random point in the closest entry region to the group of pirates</returns> private Vec2D GetPointInClosestEntryRegion(Dictionary<T_Move,T_Reveal> pirates, List<PolygonValue> entryRegions) { Vec2D point = new Vec2D(0,0); double closestDistance = 100000000; PolygonValue closestRegion = null; Shuffle(entryRegions); T_Move randomPirate = pirates.Keys.ToList().ElementAt(0); LocationValue location = GetLocation(randomPirate, pirates[randomPirate]); foreach (PolygonValue entryRegion in entryRegions) { Polygon2D entry2D = new Polygon2D(entryRegion); double distance = Polygon2D.ScalarDistanceToPolygon(entry2D, new Vec2D(location)); if (distance < oneGroupingDistance) { point = entry2D.PointInside(); break; } else { if (distance < closestDistance) { closestDistance = distance; closestRegion = entryRegion; } } } if (point == null) { point = new Polygon2D(closestRegion).PointInside(); } return point; }
public bool SpecialGenerate(T_Item currentItem, String dmID) { Dictionary<T_Move,T_Reveal> dict = GetActionsAsDictionary(currentItem.Action); Dictionary<T_Move, T_Reveal> newDict = new Dictionary<T_Move,T_Reveal>(); List<PolygonValue> seaLanes = ddd.GetAllSeaLanes(); PolygonValue domain = this.ddd.GetDecisionMakersAreaOfResponsibility(dmID); foreach (T_Move key in dict.Keys) { T_Move move = key; T_Reveal reveal = dict[key]; //Is this vessel a pirate? bool isPirate = false; if (reveal!=null) //there's a reveal event { if (reveal.Owner == "Pirate DM") isPirate = true; } else if (ddd.GetSeamateObject(move.ID).Owner == "Pirate DM") isPirate = true; //Vessel's desired perceived ambiguity bool ambiguity = true; if (currentItem.Parameters.Threat == T_Threat.Unambiguous) ambiguity = false; //If it's a merchant and resources aren't unavailable, always make merchants UNambiguous (so IFF is likely to be on) if (!isPirate && currentItem.Parameters.PlayerResources == T_ResourceAvailability.Available) ambiguity = false; //Is it in a sea lane? If it is already in play check, Yes if it is being revealed in an entry region bool locationInSeaLane = false; LocationValue location; if (reveal == null) //already in play location = ddd.GetSeamateObject(move.ID).Location; else location = (LocationValue)reveal.Location.Item; foreach (PolygonValue seaLane in seaLanes) { Polygon2D seaLane2D = new Polygon2D(seaLane); if (Polygon2D.IsPointInside(seaLane2D, new Vec2D(location))) { locationInSeaLane = true; break; } } //Intercept course bool onInterceptCourse = false; if (currentItem.Parameters.ThreatType == T_ThreatType.Imminent && isPirate) onInterceptCourse = true; //IFF bool hasIFFon = false; //Is its IFF already on? if (move == null) //Object already exists in play { String displayName = ddd.GetSeamateObject(move.ID).ObjectName; if (!displayName.StartsWith("unknown")) //Object has IFF set on hasIFFon = true; } //Pick row from ambiguity table using existing constraints. Shuffle(ambiguityTable); bool[] selectedRow = null; foreach (bool[] row in ambiguityTable) { if ((!onInterceptCourse || row[2]) //if onInterceptCourse is true, only allow course to be "on"/true ... if onInterceptCourse is false, either value is OK && (!hasIFFon || row[0]) //same as above for hasIFFon and IFF && (!locationInSeaLane || row[3]) //same as above for inSeaLane and location && ambiguity == row[4]) // ambiguity must match selectedRow = row; } if (selectedRow == null) { return false; //Console.WriteLine("Impossible scenario"); //selectedRow = ambiguityTable[random.Next(ambiguityTable.Length)]; //TODO: Wipe out actions, go back to Threat Generator and make a new object } // Console.WriteLine("AmbiguityGenerator: Making settings for an " + currentItem.Parameters.ThreatType.ToString() + " vessel. IFF should be on?" + selectedRow[0]); //Create scenario described in ambiguity table //IFF ================================= //If we're revealing a new vessel, we can set its IFF on if we need to. Default is off so we don't // have to do anything. We can't change existing ships. if (reveal != null) { if (selectedRow[0] && !isPirate) SetIFF(isPirate, reveal); //If it's a pirate, ignore what it says in the ambiguity table. //Unambiguous == IFF ON always. Ambiguous = IFF OFF always if (isPirate && currentItem.Parameters.Threat == T_Threat.Unambiguous) SetIFF(isPirate, reveal); } //SPEED =============================== double maxSpeed = GetMaxSpeed(move); double newSpeed; if (selectedRow[1]) //speed 69-84 m/s newSpeed = random.Next(69, Math.Max((int)maxSpeed,84)); else { //speed <69 or >84 m/s if (maxSpeed > 84) newSpeed = random.Next(84, (int)maxSpeed); else newSpeed = random.Next(20, 68); } move.Throttle = ((double)newSpeed / (double)maxSpeed); //COURSE ================================= if (selectedRow[2]) { if (onInterceptCourse) // we will take care of this later { } else //if (locationInSeaLane) { //pick any entry region and send it there. Polygon2D entryRegion2D = new Polygon2D(entryRegions[random.Next(entryRegions.Count)]); Vec2D point = entryRegion2D.PointInside(); move.Location = new T_Location(); move.Location.Item = point.ToLocationValue(); } } else { //just send it anywhere ... probably won't be in a sea lane Vec2D point = new Polygon2D(domain).PointInside(); //TODO: this should be in whole scenario boundaries, not just DM domain move.Location = new T_Location(); move.Location.Item = point.ToLocationValue(); //TODO: Send it to the edge of the universe. Just kidding ... to edge of sea region. ddd.GetDecisionMakersAreaOfResponsibility("BAMS DM"); ddd.GetDecisionMakersAreaOfResponsibility("Firescout DM"); } //Add modified move and reveal back to dictionary. newDict[move] = reveal; } currentItem.Action = GetActionsFromDictionary(newDict); return true; }
public override void Generate(T_Item currentItem, String dmID) { //Identify what's already in actions list. foreach (Object action in currentItem.Action) { if (action as T_Move != null) primaryMove = (T_Move)action; if (action as T_Reveal != null) primaryReveal = (T_Reveal)action; } LocationValue location = GetLocation(primaryMove, primaryReveal); bool isPirate = GetOwner(primaryMove, primaryReveal)=="Pirate DM"; PolygonValue pirateEntryRegion = null; if (isPirate) { foreach (PolygonValue region in entryRegions) { if (Polygon2D.IsPointInside(new Polygon2D(region), new Vec2D(location))) { pirateEntryRegion = region; break; } } } List<Object> list = currentItem.Action.ToList(); List<string> unrevealedObjectIDs = ddd.GetAllUnrevealedObjectIds(false, true, null); if (primaryReveal != null) unrevealedObjectIDs.Remove(primaryReveal.ID); int minStimuli = 0; //If threat type is imminent, we need to guarantee there will be a merchant for the pirate to attack. if (currentItem.Parameters.ThreatType == T_ThreatType.Imminent) minStimuli = 1; int maxStimuli; //If resources need to be available, then two is maximum of stimulus events. if (T_ResourceAvailability.Available == currentItem.Parameters.PlayerResources) maxStimuli = 2; //If resources are unavailable, there must be at least 3 total stimulus events, and max can be higher. else { minStimuli = 3; maxStimuli = 5; } int numStimuliToGenerate = this.changingNumber(minStimuli, 60, minStimuli, maxStimuli); //probably minStimuli but could be up to maxStimuli //If our probability criteria says we should add vessels, try and populate reusable objects list List<DDDAdapter.SeamateObject> reuseableObjects = new List<DDDAdapter.SeamateObject>(); if (shouldAddNewVessel(revealedSeaVessels)) reuseableObjects = findObjectsInPlay(location, pirateEntryRegion, currentItem.Parameters.Groupings, false); for (int i = 0; i < numStimuliToGenerate; i++) { T_Move move = new T_Move(); //Try and recycle objects to create stimulus. if (reuseableObjects.Count != 0) { Shuffle(reuseableObjects); DDDAdapter.SeamateObject objectForReuse = null; //see if any eligible vessels are stopped, if so, use one of them foreach (DDDAdapter.SeamateObject possiblyStoppedVessel in reuseableObjects) { if (possiblyStoppedVessel.Throttle == 0) //yes, it is stopped { //Console.WriteLine("GRoupingGenerator: Picking a stopped vessel " + possiblyStoppedVessel.ID + " to reuse."); objectForReuse = possiblyStoppedVessel; break; } } //randomly pick one of the suitable objects to create a stimulus if (objectForReuse == null) objectForReuse = reuseableObjects[random.Next(reuseableObjects.Count)]; move.ID = objectForReuse.ID; reuseableObjects.Remove(objectForReuse); //Console.WriteLine("GroupingGenerator: Moving existing merchant " + objectForReuse.ID); } else //Reveal and move new merchant. { T_Reveal reveal = new T_Reveal(); reveal.Owner = "Merchant DM"; reveal.State = "FullyFunctional"; reveal.StartupParameters = new T_StartupParameters(); reveal.StartupParameters.Items = new string[0]; reveal.ID = unrevealedObjectIDs[random.Next(unrevealedObjectIDs.Count)]; //pick a random new object unrevealedObjectIDs.Remove(reveal.ID); //take it out of the available list //ADDED 11/10/11: To make sure that the merchants don't end up in the same entry region as a newly created pirate, //if there's a new pirate, instead of iterating over all entry regions we'll remove the pirate's region from the list first. if (pirateEntryRegion != null) entryRegions.Remove(pirateEntryRegion); Vec2D point = null; //If two grouping, pick points in entry regions until one is > 100 away if (currentItem.Parameters.Groupings == T_Groupings.Two) { while (true) { point = new Polygon2D(entryRegions[random.Next(entryRegions.Count)]).PointInside(); if (point.ScalerDistanceTo(new Vec2D(location)) > twoGroupingDistance) { break; } } } //If one grouping, see if any entry region is within 50km. If so, pick a point in that entry region. //It's possible that no entry region may be within 50km. In that case, pick a point in the closest one. if (currentItem.Parameters.Groupings == T_Groupings.One) { double closestDistance = 100000000; PolygonValue closestRegion = null; Shuffle(entryRegions); foreach (PolygonValue entryRegion in entryRegions) { Polygon2D entry2D = new Polygon2D(entryRegion); double distance = Polygon2D.ScalarDistanceToPolygon(entry2D, new Vec2D(location)); if (distance < oneGroupingDistance) { point = entry2D.PointInside(); break; } else { if (distance < closestDistance) { closestDistance = distance; closestRegion = entryRegion; } } } if (point == null) { //Console.WriteLine("GroupingGenerator: Unable to place vessel in an entry region AND <100km away. Placing in closest entry region " + closestDistance + " away."); point = new Polygon2D(closestRegion).PointInside(); } } reveal.Location = new T_Location(); reveal.Location.Item = point.ToLocationValue(); list.Add(reveal); move.ID = reveal.ID; //Console.WriteLine("GroupingGenerator: Revealing new merchant " + reveal.ID + " and moving it"); } move.Location = new T_Location(); list.Add(move); } currentItem.Action = list.ToArray(); }