/// <summary> /// Returns a boolean value expressing whether or not a new vessel can be added to an existing group while fulfilling /// grouping constraints. /// One grouping: Every item in the group must be within the one-grouping parameter of each other. /// Two grouping: At least one pair in the group must be separated by the two-grouping parameter. /// </summary> /// <param name="oneOrTwo">Must be "One" or "Two" for a one- or two-grouping</param> /// <param name="newVessel">Vessel to be added to the group</param> /// <param name="otherVessels">Existing group of vessels</param> /// <returns></returns> private bool MatchesGroupingCriteria(T_Groupings grouping, DDDAdapter.SeamateObject newVessel, List <DDDAdapter.SeamateObject> otherVessels) { if (otherVessels.Contains(newVessel)) { return(false); } if (grouping == T_Groupings.One) { foreach (DDDAdapter.SeamateObject vessel in otherVessels) { double distance = new Vec2D(vessel.Location).ScalerDistanceTo(new Vec2D(newVessel.Location)); if (distance > oneGroupingDistance) { return(false); } } return(true); } else { foreach (DDDAdapter.SeamateObject vessel in otherVessels) { double distance = new Vec2D(vessel.Location).ScalerDistanceTo(new Vec2D(newVessel.Location)); if (distance > twoGroupingDistance) { return(true); } } return(false); } }
/// <summary> /// Determines whether a merchant is within grouping constraints of previously chosen pirates. /// </summary> /// <param name="vessel">Merchant</param> /// <returns>Boolean</returns> private bool MatchesGroupingConstraints(DDDAdapter.SeamateObject vessel) { if (vessel.Intent != "") { return(false); } if (grouping == T_Groupings.One) { foreach (T_Move key in dict.Keys) { Vec2D otherVesselLocation = new Vec2D(GetLocation(key, dict[key])); double distance = new Vec2D(vessel.Location).ScalerDistanceTo(otherVesselLocation); if (distance > oneGroupingDistance) { return(false); } } return(true); } else { return(true); } }
/// <summary> /// Returns a boolean value expressing whether or not a vessel is suitable to be chosen to express a stimuli. /// </summary> /// <param name="vessel"></param> /// <returns></returns> private bool IsReusable(DDDAdapter.SeamateObject vessel) { //merchants may be attacked by multiple pirates, so it's ok to choose them even if they //already have an intent. bool isMerchantOrNotOnAttackCourse = ((vessel.Owner == "Merchant DM") || (vessel.Intent == "")); return(vessel.Owner == owner && Polygon2D.IsPointInside(domain, new Vec2D(vessel.Location)) && isMerchantOrNotOnAttackCourse); }
/// <summary> /// Adds a new move event to the action list. Does not contain a destination yet /// </summary> /// <param name="vessel"></param> protected void CreateEmptyMove(DDDAdapter.SeamateObject vessel) { T_Move move = new T_Move(); move.ID = vessel.ID; move.Location = new T_Location(); actions.Add(move); }
public double GetMaxSpeed(T_Move move) { DDDAdapter.SeamateObject seamateObject = ddd.GetSeamateObject(move.ID); if (seamateObject.MaximumSpeed > 0) { return(seamateObject.MaximumSpeed); } String className = ddd.GetSeamateObject(move.ID).ClassName; //if (className.Trim() == "") //handles erroneous blank className, remove this code when Adam fixes // return 75; Dictionary <string, DataValue> speciesStateParameters = ddd.GetSpeciesStateParameters(className, "FullyFunctional"); return(((DoubleValue)speciesStateParameters["MaximumSpeed"]).value); }
/// <summary> /// Takes an EXISTING merchant and pirate and returns their shortest potential intercept time. /// </summary> /// <param name="merchant"></param> /// <param name="pirate"></param> /// <returns></returns> protected double PotentialTimeToIntercept(DDDAdapter.SeamateObject pirate, DDDAdapter.SeamateObject merchant) { Vec2D pirateLocation = new Vec2D(pirate.Location); double pirateSpeed = GetMaxSpeed(pirate); double merchantSpeed = merchant.Throttle * merchant.MaximumSpeed; Vec2D merchantStart = new Vec2D(merchant.Location); Vec2D merchantDestination = new Vec2D(merchant.DestinationLocation); Vec2D interceptPoint = GetInterceptPoint(merchantStart, merchantDestination, merchantSpeed, pirateLocation, pirateSpeed); double timeToIntercept = merchantStart.ScalerDistanceTo(interceptPoint) / merchantSpeed; return(timeToIntercept); }
protected double GetMaxSpeed(DDDAdapter.SeamateObject seamateObject) { if (seamateObject.MaximumSpeed > 0) { return(seamateObject.MaximumSpeed); } String className = seamateObject.ClassName; if (className.Trim() == "") //handles erroneous blank className, remove this code when Adam fixes { return(75); } Dictionary <string, DataValue> speciesStateParameters = ddd.GetSpeciesStateParameters(className, "FullyFunctional"); return(((DoubleValue)speciesStateParameters["MaximumSpeed"]).value); }
/// <summary> /// Checks whether an existing pirate is either positioned within a 60s attack range of an existing vessel, or within 60s of an entry region. /// </summary> /// <param name="pirate"></param> /// <returns></returns> Boolean PirateIsWithinOneMinuteAttackRange(DDDAdapter.SeamateObject pirate, List <PolygonValue> entryRegions) { foreach (DDDAdapter.SeamateObject vessel in revealedSeaVessels) { //First compare all the existing merchants' positions to see if they are within range. if (vessel.Owner == "Merchant DM") { if (PotentialTimeToIntercept(pirate, vessel) < 60) { return(true); } } else { continue; //ignore merchants or fleet ships } } //There was no existing merchant in range. Now we need to check if any entry region is in range //to possibly create a merchant there. I do this by iterating over each boundary point and checking if any of them //is reachable by the pirate in 60 seconds. foreach (PolygonValue entryRegion in entryRegions) { foreach (PolygonValue.PolygonPoint entryPoint in entryRegion.points) { Vec2D point = new Vec2D(entryPoint.X, entryPoint.Y); double distance = point.ScalerDistanceTo(new Vec2D(pirate.Location)); double timeToPoint = distance / pirate.MaximumSpeed; if (timeToPoint < 60) { return(true); } } } //If we got this far, there is no existing merchant or entry region in which to create a merchant //reachable by the pirate in 60 sec. return(false); }
//Pirate generator -- generates or chooses several pirates or friendly vessels in DM domain //So either creates a RevealEvent or chooses existing vessel for MoveEvent public override void Generate(T_Item currentItem, String dmID) { if (currentItem.Parameters.Threat == T_Threat.None) { return; } actions = currentItem.Action.ToList(); // Do some setup bool isPirate = !(currentItem.Parameters.Threat == T_Threat.None); if (isPirate) { owner = "Pirate DM"; } else { owner = "Merchant DM"; } PolygonValue domainPV = this.ddd.GetDecisionMakersAreaOfResponsibility(dmID); domain = new Polygon2D(domainPV); List <string> unrevealedObjectIDs = ddd.GetAllUnrevealedObjectIds(isPirate, true, null); //How many pirates should we generate? These numbers may need tweaking int minPirates = Properties.Settings.Default.minPirates; int maxPirates = Properties.Settings.Default.maxPirates; int numPirates = random.Next(minPirates, maxPirates); //Are there any pirates we can reuse, already in play? List <DDDAdapter.SeamateObject> reusableVessels = revealedSeaVessels.FindAll(IsReusable); if (reusableVessels.Count > 0 && Properties.Settings.Default.reusePirates) { for (int i = 0; i < numPirates; i++) { if (reusableVessels.Count > 0) { DDDAdapter.SeamateObject vessel = reusableVessels[0]; reusableVessels.Remove(vessel); CreateEmptyMove(vessel); } else { Vec2D location = MakeLocationInEntryRegions(entryRegions); string id = unrevealedObjectIDs[random.Next(unrevealedObjectIDs.Count())]; unrevealedObjectIDs.Remove(id); CreateRevealAndEmptyMove(id, owner, location); } } ////See if any existing pirates can be paired under "grouping" distance constraints //List<List<DDDAdapter.SeamateObject>> groupedPirates = GroupVessels(currentItem.Parameters.Groupings, numPirates, reusableVessels); //List<List<DDDAdapter.SeamateObject>> groupsOfNumPirateSize = groupedPirates.FindAll(delegate(List<DDDAdapter.SeamateObject> g) { return g.Count >= numPirates; }); ////Any groups of numPirates? //if (groupsOfNumPirateSize.Count > 0) //{ // //if yes, make dummy move events for them and add to actions list. done. // foreach (DDDAdapter.SeamateObject pirate in groupsOfNumPirateSize.ElementAt(0)) // CreateEmptyMove(pirate); //} //else //{ // //Can any of these smaller groupings include an entry region too, so we can add new pirates? // groupedPirates.Sort(delegate(List<DDDAdapter.SeamateObject> g1, List<DDDAdapter.SeamateObject> g2) { return g1.Count.CompareTo(g2.Count); }); //sort by size, largest first // foreach (List<DDDAdapter.SeamateObject> group in groupedPirates) // { // List<PolygonValue> matchingEntryRegions = GetMatchingEntryRegions(currentItem.Parameters.Groupings, group, entryRegions); // if (matchingEntryRegions.Count > 0) // { // //if yes, then make dummy move events for the pirates in grouping, then // foreach (DDDAdapter.SeamateObject pirate in groupsOfNumPirateSize.ElementAt(0)) // CreateEmptyMove(pirate); // //Create as many remaining pirates as we need distributed randomly among suitable entry regions. // List<Vec2D> locations = MakeLocationsInEntryRegions(numPirates - group.Count, matchingEntryRegions); // foreach (Vec2D location in locations) // { // string id = unrevealedObjectIDs[random.Next(unrevealedObjectIDs.Count())]; // unrevealedObjectIDs.Remove(id); // CreateRevealAndEmptyMove(id, owner, location); // } // break; // } // } // //if no, we couldn't include an entry region (where new pirates would be created) with any existing pirates // if (actions.Count == 0) // //TODO: maybe should make smaller num of pirates if above min rather than making all new? // MakeAllNewPirates(currentItem.Parameters.Groupings,numPirates,entryRegions,unrevealedObjectIDs); //} } //no reusable vessels, we have to create all new pirates else { MakeAllNewPirates(currentItem.Parameters.Groupings, numPirates, entryRegions, unrevealedObjectIDs); } currentItem.Action = actions.ToArray(); }
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(); }
//Threat generator -- generates or chooses ONE pirate or friendly vessel in DM domain //So either creates a RevealEvent or chooses existing vessel for MoveEvent public List <DDDAdapter.SeamateObject> GenerateWithTriedItems(T_Item currentItem, String dmID, List <DDDAdapter.SeamateObject> triedVessels) { //make a copy of the input which we'll modify and return at the end List <DDDAdapter.SeamateObject> returnTriedVessels = new List <DDDAdapter.SeamateObject>(triedVessels); String owner; bool isPirate; if (currentItem.Parameters.Threat == T_Threat.None) { isPirate = false; owner = "Merchant DM"; } else { isPirate = true; owner = "Pirate DM"; } PolygonValue domainPV = this.ddd.GetDecisionMakersAreaOfResponsibility(dmID); Polygon2D domain = new Polygon2D(domainPV); List <Object> actions = new List <object>(); if (shouldAddNewVessel(revealedSeaVessels)) { Console.WriteLine("ThreatGenerator: I'm trying to reuse a vessel because there are " + revealedSeaVessels.Count + " in play already and/or probability told me to."); List <DDDAdapter.SeamateObject> vessels = new List <DDDAdapter.SeamateObject>(); //Find all vessels of the appropriate type (pirate or merchant) within the BAMS/Firescout's range. foreach (DDDAdapter.SeamateObject vessel in revealedSeaVessels) { if (vessel.Owner == owner && Polygon2D.IsPointInside(domain, new Vec2D(vessel.Location))) { vessels.Add(vessel); } } Console.WriteLine("ThreatGenerator: Found " + vessels.Count + " to reuse"); if (vessels.Count > 0) { //manage the list of previously tried objects if (triedVessels.Count == vessels.Count) { returnTriedVessels = new List <DDDAdapter.SeamateObject>(); } foreach (DDDAdapter.SeamateObject alreadyTried in returnTriedVessels) { vessels.Remove(alreadyTried); } Shuffle(vessels); DDDAdapter.SeamateObject vessel = null; //see if any eligible vessels are stopped, if so, use one of them foreach (DDDAdapter.SeamateObject possiblyStoppedVessel in vessels) { if (possiblyStoppedVessel.Throttle == 0) //yes, it is stopped { Console.WriteLine("ThreatGenerator: Picking a stopped vessel " + possiblyStoppedVessel.ID + " to reuse."); vessel = possiblyStoppedVessel; break; } } //we didn't find any stopped vessels, so pick a random eligible one. if (vessel == null) { vessel = vessels[random.Next(vessels.Count)]; } returnTriedVessels.Add(vessel); T_Move move = new T_Move(); move.ID = vessel.ID; move.Location = new T_Location(); actions.Add(move); } } if (actions.Count() == 0) //we couldn't find a ship or need more vessels { //reveal a random new one Console.WriteLine("ThreatGenerator: I'm revealing a new vessel, either couldn't find a ship or need more vessels."); List <string> unrevealedObjectIDs = ddd.GetAllUnrevealedObjectIds(isPirate, true, null); T_Reveal reveal = new T_Reveal(); reveal.ID = unrevealedObjectIDs[random.Next(unrevealedObjectIDs.Count())]; reveal.Owner = owner; reveal.State = "FullyFunctional"; reveal.Location = new T_Location(); reveal.StartupParameters = new T_StartupParameters(); reveal.StartupParameters.Items = new string[0]; T_Move move = new T_Move(); move.ID = reveal.ID; move.Location = new T_Location(); Vec2D point; List <PolygonValue> entryRegions = ddd.GetAllEntryRegions(); //TODO: Write a safe PointInsideMultipleDomains() function. This could theoretically loop forever with a terrible scenario while (true) { point = new Polygon2D(entryRegions[random.Next(entryRegions.Count)]).PointInside(); if (Polygon2D.IsPointInside(domain, point)) { break; } } reveal.Location.Item = point.ToLocationValue(); actions.Add(reveal); actions.Add(move); Console.WriteLine("ThreatGenerator: Just revealed a pirate " + reveal.ID); } currentItem.Action = actions.ToArray(); return(returnTriedVessels); }
/// <summary> /// Calculates an intercept course for all pirates /// </summary> /// <param name="currentItem"></param> /// <param name="dmID"></param> public override void Generate(T_Item currentItem, String dmID) { Dictionary <T_Move, T_Reveal> dict = GetActionsAsDictionary(currentItem.Action); //Make new dictionaries; they will be copies containing either merchants or pirates Dictionary <T_Move, T_Reveal> merchantsDict = new Dictionary <T_Move, T_Reveal>(); Dictionary <T_Move, T_Reveal> piratesDict = new Dictionary <T_Move, T_Reveal>(); //Copy pirates and merchants into dictionaries foreach (T_Move key in dict.Keys) { if (GetOwner(key, dict[key]) == "Pirate DM") { piratesDict.Add(key, dict[key]); } else { merchantsDict.Add(key, dict[key]); } } if (piratesDict.Keys.Count == 0) { return; } //This dictionary of pirates is the one we'll use to save intercept courses. Dictionary <T_Move, T_Reveal> piratesWithInterceptCourse = new Dictionary <T_Move, T_Reveal>(); //Set each pirate on the shortest intercept course to a newly revealed or existing merchant. foreach (T_Move pirateMove in piratesDict.Keys) { Vec2D pirateLocation = new Vec2D(GetLocation(pirateMove, piratesDict[pirateMove])); //=========Check newly revealed merchants created in this item to find closest ===========================// double timeToIntercept = 1000000000000000; Vec2D closestInterceptPoint = null; T_Move closestNewMerchant = null; foreach (T_Move merchantMove in merchantsDict.Keys) { double merchantSpeed = merchantMove.Throttle * GetMaxSpeed(merchantMove); Vec2D merchantStart = new Vec2D(GetLocation(merchantMove, merchantsDict[merchantMove])); Vec2D merchantDestination = new Vec2D((LocationValue)merchantMove.Location.Item); Vec2D interceptPoint = GetInterceptPoint(merchantStart, merchantDestination, merchantSpeed, pirateLocation, GetMaxSpeed(pirateMove)); double merchantTimeToIntercept = merchantStart.ScalerDistanceTo(interceptPoint) / merchantSpeed; if (merchantTimeToIntercept < timeToIntercept) { closestNewMerchant = merchantMove; closestInterceptPoint = interceptPoint; timeToIntercept = merchantTimeToIntercept; } } //============Check merchants already revealed, see if one is closer ======================== //TODO: make sure any merchants we will move in this round are not being compared DDDAdapter.SeamateObject closestRevealedMerchant = null; foreach (DDDAdapter.SeamateObject vessel in revealedSeaVessels) { //Compare all the existing merchants' positions to see if they are closer. //if (vessel.ID == closestNewMerchant.ID) continue; if (vessel.Owner == "Merchant DM") { double merchantSpeed = vessel.Throttle * vessel.MaximumSpeed; Vec2D merchantStart = new Vec2D(vessel.Location); Vec2D merchantDestination = new Vec2D(vessel.DestinationLocation); Vec2D interceptPoint = GetInterceptPoint(merchantStart, merchantDestination, merchantSpeed, pirateLocation, GetMaxSpeed(pirateMove)); double merchantTimeToIntercept = merchantStart.ScalerDistanceTo(interceptPoint) / merchantSpeed; if (merchantTimeToIntercept < timeToIntercept) { closestNewMerchant = null; closestRevealedMerchant = vessel; closestInterceptPoint = interceptPoint; timeToIntercept = merchantTimeToIntercept; } } else { continue; //ignore pirates or fleet ships } } if (closestInterceptPoint == null) { return; } //Make a new move for the pirate, containing the pirate's intercept course. T_Move moveWithInterceptCourse = new T_Move(); moveWithInterceptCourse.ID = pirateMove.ID; moveWithInterceptCourse.Throttle = 1.0; moveWithInterceptCourse.Location = new T_Location(); moveWithInterceptCourse.Location.Item = closestInterceptPoint.ToLocationValue(); //Set the pirate and merchant's "Intent" relating to the intercept in their SimObjects if (closestNewMerchant != null) { ddd.UpdateObjectAttribute(closestNewMerchant.ID, "Intent", "Being intercepted:" + pirateMove.ID + ":" + timeToIntercept, "AGENT"); //Merchant ddd.UpdateObjectAttribute(pirateMove.ID, "Intent", "Intercepting:" + closestNewMerchant.ID + ":" + timeToIntercept, "AGENT"); //Pirate } else if (closestRevealedMerchant != null) { ddd.UpdateObjectAttribute(closestRevealedMerchant.ID, "Intent", "Being intercepted:" + pirateMove.ID + ":" + timeToIntercept, "AGENT"); //Merchant ddd.UpdateObjectAttribute(pirateMove.ID, "Intent", "Intercepting:" + closestRevealedMerchant.ID + ":" + timeToIntercept, "AGENT"); //Pirate } else { Console.Error.WriteLine("Fix intercept generator"); } //Add the pirate's updated move and reveal to pirate dictionary. piratesWithInterceptCourse[moveWithInterceptCourse] = piratesDict[pirateMove]; } //Add altered pirates back to merchants, and reset the action array. currentItem.Action = GetActionsFromDictionary(merchantsDict.Concat(piratesWithInterceptCourse).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); }
private static bool onlyMerchant(DDDAdapter.SeamateObject vessel) { return(vessel.Owner == "Merchant DM"); }
/// <summary> /// Returns a boolean value expressing whether or not a vessel is stopped. /// </summary> /// <param name="vessel"></param> /// <returns></returns> protected bool IsStopped(DDDAdapter.SeamateObject vessel) { return(vessel.Throttle == 0); }
public override void Generate(T_Item currentItem, String dmID) { actions = currentItem.Action.ToList(); dict = GetActionsAsDictionary(currentItem.Action); grouping = currentItem.Parameters.Groupings; List <string> unrevealedMerchantIDs = ddd.GetAllUnrevealedObjectIds(false, true, null); //Gets only merchants int 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 = Properties.Settings.Default.resourceThreshold - 1; } //If resources are unavailable, there must be at least 3 total stimulus events, and max can be higher. else { minStimuli = Properties.Settings.Default.resourceThreshold; maxStimuli = Properties.Settings.Default.resourceThreshold * 2 - 1; } int numPirates = dict.Keys.Count; int numMerchants = Math.Max(0, random.Next(minStimuli, maxStimuli) - numPirates); if (numMerchants == 0) { return; } //If our probability criteria says we should add vessels, let's see if we can reuse any existing vessels List <DDDAdapter.SeamateObject> reuseableVessels = new List <DDDAdapter.SeamateObject>(); List <DDDAdapter.SeamateObject> allExistingMerchants = revealedSeaVessels.FindAll(IsMerchant); if (shouldAddNewVessel(revealedSeaVessels)) { reuseableVessels = allExistingMerchants.FindAll(MatchesGroupingConstraints); } for (int i = 0; i < numMerchants; i++) //Do once for each merchant we need to create. { //Try and recycle objects to create stimulus. if (reuseableVessels.Count > 0) { DDDAdapter.SeamateObject objectForReuse = null; //Make sure we reuse any stopped objects first List <DDDAdapter.SeamateObject> stoppedObjects = reuseableVessels.FindAll(IsStopped); if (stoppedObjects.Count > 0) { objectForReuse = stoppedObjects[random.Next(stoppedObjects.Count)]; } else { objectForReuse = reuseableVessels[random.Next(reuseableVessels.Count)]; } CreateEmptyMove(objectForReuse); reuseableVessels.Remove(objectForReuse); } else //Reveal and move new merchant starting at an appropriate point for grouping constraints. { Vec2D location = null; if (currentItem.Parameters.Groupings == T_Groupings.One) //Get point in closest entry region { location = GetPointInClosestEntryRegion(dict, entryRegions); } else if (currentItem.Parameters.Groupings == T_Groupings.Two) //Get point in any entry region { location = new Polygon2D(entryRegions[random.Next(entryRegions.Count)]).PointInside(); } string id = unrevealedMerchantIDs[random.Next(unrevealedMerchantIDs.Count)]; CreateRevealAndEmptyMove(id, "Merchant DM", location); unrevealedMerchantIDs.Remove(id); } } currentItem.Action = actions.ToArray(); }
private bool IsMerchant(DDDAdapter.SeamateObject vessel) { return(vessel.Owner == "Merchant DM"); }