/// <summary> /// Populates the NeedGroupUIs with all the needed elements /// </summary> public void DisplayObjects() { if (lastShownMapElement != selectedMapElement) { lastShownMapElement = selectedMapElement; List <PropertyOwnership> needs = selectedMapElement.propertyManager.GetPropertiesWithPriority(Property.NeedPriority.None); if (needs == null) { return; } Debug.Log($"Setting up UI for group of needs (Properties) with length {needs.Count}:\n ● {needs.ToStringAllElements("\n ● ")}\n", gameObject); // Instantiate missing UI elements int missingUIElements = needs.Count - propertyUIs.Count; for (int e = 0; e < missingUIElements; e++) { GameObject spawnedPropertyUI = Instantiate(propertyUIPrefab, propertiesArea.transform); PropertyUI propertyUI = spawnedPropertyUI.GetComponentRequired <PropertyUI>(); propertyUIs.Add(propertyUI); } // Configure the UI elements for (int e = 0; e < propertyUIs.Count; e++) { PropertyOwnership propertyOwnershipToDisplay = needs.Count > e ? needs[e] : null; propertyUIs[e].Setup(propertyOwnershipToDisplay); } } }
/// <summary> /// Displays the given Property as the objective in the UI /// </summary> /// <param name="newObjectiveProperty">The PropertyOwnership that is the objective Property to display in the UI.</param> public void DisplayObjectiveProperty(PropertyOwnership newObjectiveProperty) { bool showObjectivePropertyUI = newObjectiveProperty != null; objectivePropertyUI.gameObject.SetActive(showObjectivePropertyUI); if (showObjectivePropertyUI) { objectivePropertyUI.Setup(newObjectiveProperty); } }
public PropertyOwnershipViewModel(PropertyOwnership entity, Action <PropertyOwnershipViewModel> act = null) { if (entity == null) { return; } Entity = entity; act?.Invoke(this); }
/// <summary> /// Displays the given Property in the UI. Disables the GameObject if the Property is null. /// </summary> /// <param name="propertyOwnershipp">The PropertyOwnership to display in the UI.</param> public void Setup(PropertyOwnership propertyOwnership) { bool display = propertyOwnership != null; gameObject.SetActive(display); this.propertyOwnership = propertyOwnership; if (display) { propertyName.text = propertyOwnership.property.name; } }
/// <summary> /// Indicates if the consequences of the execution of this event will increase the value of an property owned by a map element. /// </summary> /// <param name="propertyOwnershipToCover">PropertyOwnership to cover.</param> /// <param name="executer">The MapElement that is going to execute/trigger the event.</param> /// <param name="target">The MapElement target of the execution of the event.</param> /// <param name="owner">The MapElement that owns the event.</param> /// <param name="containerProperty">The Property containing the MapEvent</param> /// <returns>True, if the execution of this MapEvent with this target, executer and owner would increase the value of the given property. False, otherwise.</returns> public bool ConsequencesCover(PropertyOwnership propertyOwnershipToCover, MapElement target, MapElement executer, MapElement owner, Property containerProperty) { bool consequenceCoversOwnerOfProperty = false; // Debug.Log($"$$$$$ Checking if consequences of '{name}' cover '{propertyOwnershipToCover.property}'. target = {target}, executer = {executer}, owner = {owner}\n"); foreach (Consequence consequence in consequences) { // Debug.Log($" $$$$$ Current consequence's property = '{consequence.property}'. Delta value = {consequence.deltaValue}. Covers desired property? {(consequence.property == propertyOwnershipToCover.property && consequence.deltaValue > 0)}\n"); if (consequence.GetProperty(containerProperty) == propertyOwnershipToCover.property && consequence.deltaValue > 0) { switch (consequence.affectedMapElement) { case AffectedMapElement.eventOwner: consequenceCoversOwnerOfProperty = propertyOwnershipToCover.owner == owner; break; case AffectedMapElement.eventExecuter: consequenceCoversOwnerOfProperty = propertyOwnershipToCover.owner == executer; break; case AffectedMapElement.eventTarget: consequenceCoversOwnerOfProperty = propertyOwnershipToCover.owner == target; break; default: throw new ArgumentOutOfRangeException(); } if (consequenceCoversOwnerOfProperty) { if (consequence.affectedMapElement == AffectedMapElement.eventTarget) { // The 'target' must not be the 'executer' neither the 'owner' if (target == executer || target == owner) { return(false); } return(true); } else { return(true); } } } } return(false); }
/// <summary> /// Returns a list of the requirements that are not met at the moment to execute the event, it and outputs a list of the value missing for each one of the requirements that are not met (in the same order). /// </summary> /// <param name="containerProperty">The Property containing the MapEvent</param> /// <param name="executer">The MapElement that is going to execute/trigger the event.</param> /// <param name="target">The MapElement target of the execution of the event.</param> /// <param name="owner">The MapElement that owns the event.</param> /// <param name="executionTimes">The amount of times that is desired to execute the event.</param> /// <returns>A list of the requirements that are not met at the moment to execute the event (the keys), each one of them related to the value missing (value to cover)</returns> public Dictionary <PropertyOwnership, float> GetRequirementsNotMet(Property containerProperty, MapElement executer, MapElement target, MapElement owner, int executionTimes) { Dictionary <PropertyOwnership, float> requirementsNotMet = new Dictionary <PropertyOwnership, float>(); foreach (Requirement requirement in requirements) { //if (requirement.property == null) // Debug.LogWarning($"Found a requirement without a property linked to it. Requirement: {requirement.ToString()}"); //OwnedProperty propertyThatMostCloselyMeetsTheRequirement; float remainingValueToCoverRequirementNotMet; bool meets = true; switch (requirement.affectedMapElement) { case AffectedMapElement.eventOwner: meets = owner.propertyManager.CanCover(containerProperty, requirement, executionTimes, out remainingValueToCoverRequirementNotMet); if (!meets) { PropertyOwnership req = (owner.propertyManager.GetOwnedPropertyAndAddItIfNotFound(requirement.GetProperty(containerProperty))); requirementsNotMet.Add(req, remainingValueToCoverRequirementNotMet); } break; case AffectedMapElement.eventExecuter: meets = executer.propertyManager.CanCover(containerProperty, requirement, executionTimes, out remainingValueToCoverRequirementNotMet); if (!meets) { PropertyOwnership req = (executer.propertyManager.GetOwnedPropertyAndAddItIfNotFound(requirement.GetProperty(containerProperty))); requirementsNotMet.Add(req, remainingValueToCoverRequirementNotMet); } break; case AffectedMapElement.eventTarget: meets = target.propertyManager.CanCover(containerProperty, requirement, executionTimes, out remainingValueToCoverRequirementNotMet); if (!meets) { PropertyOwnership req = (target.propertyManager.GetOwnedPropertyAndAddItIfNotFound(requirement.GetProperty(containerProperty))); requirementsNotMet.Add(req, remainingValueToCoverRequirementNotMet); } break; default: throw new ArgumentOutOfRangeException(); } } return(requirementsNotMet); }
/// <summary> /// Recursively look for all MapEvents available in the game's map that, as consequence of the event, they make a desired property value increase for the owner/executer/target (the needed participant). /// </summary> /// <param name="propertyOwnershipToCover">PropertyOwnership to increase the value of.</param> /// <param name="valueToCover">The amount of value needed to be covered (increased).</param> /// <param name="executer">Map element that is going to execute the list of ExecutionPlans.</param> /// <param name="mapEventsToExecute">Execution plans wanted to be executed previously to the ones to cover the propertyToCover.</param> /// <param name="iteration">The iteration number of the this method's recursive execution. Should start as 0.</param> /// <returns>An ordered list of the Execution Plans needed to achieve the goal (to increase the value of the propertyToCover by valueToCover)</returns> public List<ExecutionPlan> GetExecutionPlanToCover(PropertyOwnership propertyOwnershipToCover, float valueToCover, MapElement executer, List<ExecutionPlan> mapEventsToExecute = null, int iteration = 0) { if (iteration >= 50) { Debug.LogWarning($" ◙ Stopping the search of an execution plan to cover '{valueToCover}' of '{propertyOwnershipToCover.property}' after {iteration} iterations.\n"); mapEventsToExecute.DebugLog("\n - ", " ◙ So far, the execution path found was: \n"); return null; } Debug.Log($" ◌ Searching for an execution plan to cover '{valueToCover}' of '{propertyOwnershipToCover.property}' owned by '{propertyOwnershipToCover.owner}' executed by '{executer}'. Iteration {iteration}.\n"); if (mapEventsToExecute == null) mapEventsToExecute = new List<ExecutionPlan>(); ExecutionPlan lastExecutionPlan = mapManager.GetExecutionPlanToCover(propertyOwnershipToCover, valueToCover, executer); //if (lastExecutionPlan != null) Debug.Log($" ◍ Execution plan for covering '{ownedProperty.property}' in '{ownedProperty.ownerMapElement}' is -> {lastExecutionPlan}\n"); //else Debug.LogWarning($" ◍ No execution plan for covering '{ownedProperty.property}' in '{ownedProperty.ownerMapElement}' could be found using the 'Map.GetExecutionPlanToTakeCareOf()'.\n"); //Debug.Log($" ◍ Found Execution Plan: {lastExecutionPlan}\n"); if (lastExecutionPlan != null) { mapEventsToExecute.Add(lastExecutionPlan); Dictionary<PropertyOwnership, float> requirementsNotMet = lastExecutionPlan.GetRequirementsNotMet(); if (!requirementsNotMet.IsNullOrEmpty()) { KeyValuePair<PropertyOwnership, float> reqNotMet = requirementsNotMet.ElementAt(0); mapEventsToExecute = GetExecutionPlanToCover(reqNotMet.Key, reqNotMet.Value, executer, mapEventsToExecute, iteration+1); } } else { Debug.LogWarning($" ◙ An execution plan to cover '{valueToCover}' of '{propertyOwnershipToCover.property}' was not found (at the iteration: {iteration}). The previously found execution plans were:\n ● {mapEventsToExecute.ToStringAllElements("\n ● ")}\n", gameObject); return null; } return mapEventsToExecute; }
/// <summary> /// Look for all MapEvents available in the map that, as consequence of a MapEvent in an Property they own, they make a desired PropertyOwnership's value increase for the owner/executer/target (the needed participant). /// </summary> /// <param name="propertyOwnershipToCoverr"> The PropertyOwnership to increase the value of.</param> /// <param name="valueToCover">The amount of value needed to be covered (increased).</param> /// <param name="executer">Map element that is going to execute the ExecutionPlan.</param> /// <returns>The Execution Plan needed to achieve the goal (to increase the value of the propertyToCover by valueToCover)</returns> public ExecutionPlan GetExecutionPlanToCover([NotNull] PropertyOwnership propertyOwnershipToCover, float valueToCover, MapElement executer) { ExecutionPlan foundExecutionPlan = null; //Trying to cover with an property/mapEvent in the target foundExecutionPlan = propertyOwnershipToCover.owner.propertyManager.GetExecutionPlanToCover(propertyOwnershipToCover, valueToCover, executer); //Trying to cover with an property/mapEvent in the caregiver/executer if (foundExecutionPlan == null) { foundExecutionPlan = executer.propertyManager.GetExecutionPlanToCover(propertyOwnershipToCover, valueToCover, executer); } //Trying to cover with an property/mapEvent in any map element if (foundExecutionPlan == null) { List <MapElement> alreadyScanned = new List <MapElement>(); while (alreadyScanned.Count < existentMapElements.Count) { MapElement scanning = GetClosestMapElementTo(propertyOwnershipToCover.owner.transform.position, alreadyScanned); ExecutionPlan foundMapEvent = scanning.propertyManager.GetExecutionPlanToCover(propertyOwnershipToCover, valueToCover, executer); if (foundMapEvent != null) { return(foundMapEvent); } else { alreadyScanned.Add(scanning); // Todo: Do something to delay the process and reduce the load on the CPU due to the search with sorting by proximity //Wait(30f/existentMapElements.Count); // Para que siempre, si tuviera que pensar en TODOS los MapELements del mapa, tardaria 30s en pensarselo indiferentemente de la cantidad de MapElements existentes } } } return(foundExecutionPlan); }
void Start() { Instance = this; }
/// <summary> /// Sets the amount of times remaining to execute this plan's MapEvent to the same amount needed to to cover a given property (to increase its value a defined amount). /// </summary> /// <param name="propertyOwnershipToCoverr">PropertyOwnership that is desired to cover (to increase its value in the MapElement's PropertyManager)</param> /// <param name="remainingValueToCover">The remaining value to cover for the given Property.</param> public void SetExecutionTimesToCover(PropertyOwnership propertyOwnershipToCover, float remainingValueToCover) { this.executionTimes = CalculateExecutionsNeededToCover(propertyOwnershipToCover, remainingValueToCover); }
/// <summary> /// Calculates the amount of times that the execution of this ExecutionPlan's MapElement is needed to cover a given property (to increase its value a defined amount). /// </summary> /// <param name="propertyOwnershipToCover">PropertyOwnership that is desired to cover (to increase its value in the MapElement's PropertyManager)</param> /// <param name="remainingValueToCover">The remaining value to cover for the given Property.</param> /// <returns></returns> private int CalculateExecutionsNeededToCover(PropertyOwnership propertyOwnershipToCover, float remainingValueToCover) { float coveredPerExecution = 0; //Debug.LogWarning($"Calculating how many times '{this.mapEvent}' must be executed to cover '{ownedPropertyToCover.property}'..."); foreach (Consequence consequence in mapEvent.consequences) { //Debug.Log($"CHECKING {consequence.property} against {ownedPropertyToCover.property}"); if (consequence.GetProperty(this.property) == propertyOwnershipToCover.property) { switch (consequence.affectedMapElement) { case AffectedMapElement.eventOwner: if (this.eventOwner == propertyOwnershipToCover.owner) { coveredPerExecution += consequence.deltaValue; } break; case AffectedMapElement.eventExecuter: if (this.executer == propertyOwnershipToCover.owner) { coveredPerExecution += consequence.deltaValue; } break; case AffectedMapElement.eventTarget: if (this.target == propertyOwnershipToCover.owner) { coveredPerExecution += consequence.deltaValue; } break; default: throw new ArgumentOutOfRangeException(); } } } int result = -1; if (coveredPerExecution > 0) { result = (int)Math.Ceiling(((double)remainingValueToCover) / ((double)coveredPerExecution)); } //Debug.LogWarning($"It needs to be executed {result} times to cover {remainingValueToCover} of remaining value. It covers {coveredPerExecution} per execution."); if (coveredPerExecution >= remainingValueToCover) { return(1); } if (coveredPerExecution > 0) { return(result); } // Debug.LogWarning($"'{this}' can not cover '{ownedPropertyToCover}'."); return(-1); }