public void ChangeCurrentWorldState(GOAP_Worldstate newState) { if (currentWorldstates.ContainsKey(newState)) { if (newState.type == WorldStateType.UNIQUE) { currentWorldstates.Remove(newState); //this should find the state based on the key only currentWorldstates.Add(newState); Debug.Log(Character.characterData.characterName + " <color=#cc0000>Updated state:</color> " + newState.ToString()); } else { if (!currentWorldstates.ContainsExactly(newState)) { Character.Log(Character.characterData.characterName + " <color=#cc0000>Add state:</color> " + newState.ToString()); currentWorldstates.Add(newState); } } } //Otherwise, if the newstate is not contained in the currentworldstate, add it else { Character.Log(Character.characterData.characterName + " <color=#cc0000>Add state:</color> " + newState.ToString()); currentWorldstates.Add(newState); } }
/// <summary> /// This action chooses a goal from among the personal goals after checking if there are completed quests to finish first /// </summary> public void ChooseGoal() { activeGoal.Clear(); string msg = "<color=#0000cc><b>CHECKING GOALS</b>:" + character.characterData.characterName + "</color>\n"; //Check goals top to bottom, to see which need to be fulfilled for (int i = 0; i < character.characterData.goals.Count; i++) { GOAP_Worldstate goal = character.characterData.goals[i]; //Check if the goal is already satisfied if (!GOAP_Planner.IsGoalSatisfied(currentWorldstates, goal)) { //And if it has been checked before if (!checkedCharacterGoals.ContainsExactly(goal)) { checkedCharacterGoals.Add(character.characterData.goals[i]); activeGoal.Add(goal); msg += character.characterData.goals[i].key + ":" + character.characterData.goals[i].value + " not yet satisfied\n"; break; } else { msg += character.characterData.goals[i].key + ":" + character.characterData.goals[i].value + " not yet satisfied, but was already checked\n"; } } else { if (checkedCharacterGoals.ContainsExactly(character.characterData.goals[i])) { checkedCharacterGoals.Remove(character.characterData.goals[i]); } msg += character.characterData.goals[i].key + ":" + character.characterData.goals[i].value + " already satisfied\n"; } } Character.Log(msg); timeSincePlanned = 0.0f; }
/// <summary> /// Combines current and goal worldstate /// </summary> /// <param name="currentWorldState"></param> /// <param name="goalWorldState"></param> /// <returns></returns> private static Node GetGoalNode(List_GOAP_Worldstate currentWorldState, List_GOAP_Worldstate goalWorldState) { List_GOAP_Worldstate newRequired = new List_GOAP_Worldstate(goalWorldState); plannerLog += "Found Goal:\n"; for (int state = 0; state < goalWorldState.Count; state++) { plannerLog += goalWorldState[state].ToString() + "\n"; if (currentWorldState.ContainsExactly(goalWorldState[state])) { newRequired.Remove(goalWorldState[state]); } } plannerLog += "\n"; return(new Node(null, newRequired, null, 0)); }
private static Node GetValidNeighborNode(Node activeNode, GOAP_Action action, List_GOAP_Worldstate planningWorldState, GOAP_Agent agent) { bool isUsefulAction = false; List_GOAP_Worldstate newRequired = new List_GOAP_Worldstate(activeNode.required); //Actions need to fulfill at least one required Worldstate to result in a valid neighbor foreach (GOAP_Worldstate state in activeNode.required) { if (action.SatisfyWorldstates.ContainsExactly(state)) { if (state.key == WorldStateKey.bWasFieldTended && state.value == 0) { Debug.LogError(action.SatisfyWorldstates.ToString()); } newRequired.Remove(state); isUsefulAction = true; } } //if this action does not help the plan, return null if (!isUsefulAction) { return(null); } //If the actions proceduralConditions are not met, we can't perform it anyways //if (!action.CheckProceduralConditions(agent)) return null; //add the actions own required worldstates to the Node foreach (GOAP_Worldstate state in action.RequiredWorldstates) { if (!planningWorldState.ContainsExactly(state)) { //If the state is an observable one and the agent does not have any memory of it, they just assume that it is in their favor if (state.IsObservableState && !agent.currentWorldstates.ContainsKey(state)) { Debug.Log("<color=#cc00cc>" + agent.Character.characterData.characterName + "</color> assumes state:" + state.ToString()); agent.ChangeCurrentWorldState(state); } else { newRequired.Add(state); } } } //Apply skillmodification onto the neighbor if it is valid float skillModifier = 1f; if (action.BenefitingSkill != Skills.None) { GOAP_Skill skill = agent.Character.characterData.skills.Find(x => x.id == action.BenefitingSkill); if (skill != null) { //If the character is actually skilled in this action, adjust the skillmodifier skillModifier /= skill.level; } else { //If the character is not skilled in this action, the skillmodifier is set to 5. This only comes into play, when global knowledge planning is used. skillModifier = 1f; } } //Change the skillmodifier on the action action.ApplySkillModifier(skillModifier); return(new Node(activeNode, newRequired, action, newRequired.Count * heuristicFactor + action.ActionCost + activeNode.estimatedPathCost)); }