/// <summary> /// evaluate given state-prob pair /// </summary> /// <param name="current">current confict state, without any applied actions</param> /// <param name="pairs">pairs to evaluate</param> /// <param name="character">npc character</param> /// <returns>calculated cost of given pairs</returns> private int ComputeCost(ConflictState current, StateProbPairs pairs, CharacterNPC character) { int cost = 0; ConflictState state; for (int i = 0; i < pairs.states.Count; i++) { state = pairs.states[i]; if (state.myHP > character.hp) { state.myHP = character.hp; } if (state.myMana > character.mana) { state.myMana = character.mana; } int myHpRating = 0, enemyHpRating = 0, boostRating = 0, manaRating = 0; if (state.myHP > current.myHP) { myHpRating = current.myHP; } else if (state.myHP < current.myHP) { myHpRating = current.myHP - state.myHP; //self harm } if (state.myMana - current.myMana >= 80) { manaRating = current.myMana; } else if (state.myMana < current.myMana) { manaRating = state.myMana - current.myMana; } if (state.enemyHP < current.enemyHP) { enemyHpRating = state.enemyHP; } boostRating = 0;// character.mana - state.myMana; int energyRating = (current.myEnergy - state.myEnergy) * 10; int timeRating = pairs.action.time / 10; int sum = myHpRating + enemyHpRating + boostRating + energyRating + manaRating + timeRating; sum *= (pairs.probabilities[i]); sum /= 100; cost += sum; } cost /= pairs.states.Count; return(cost); }
/// <summary> /// from generated state-prob pairs choose the best one and returns new Confict state /// </summary> /// <param name="myself">npc, which is choosing from actions</param> /// <param name="enemy">enemy npc on which is the target</param> /// <param name="priors">priors from npc character, useless for now</param> /// <param name="actionType">type of action</param> /// <returns>new confict state</returns> public ConflictState GetNextAction(IActing myself, IActing enemy, Priorities priors, out Action selectedAction) { ConflictState currentState = new ConflictState(myself.GetStatus(), enemy.GetStatus()); Priorities priorities = priors; CharacterNPC myChar = myself.GetCharacter(); //if (this.stateSpace.Count == 0) //{ // CreateStateSpace(currentState, myChar); //} List <StateProbPairs> expanders = Expand(currentState, myChar); StateProbPairs result = new StateProbPairs(); int lowestCost = int.MaxValue; int actionCost = int.MaxValue; foreach (StateProbPairs pairs in expanders) { //if (this.stateSpace.Contains(pairs)) //{ // Logging.Logger.AddInfo(pairs.ToString() + " je obsazeno"); //} actionCost = ComputeCost(currentState, pairs, myChar); if (actionCost < lowestCost && actionCost >= 0) { result = pairs; lowestCost = actionCost; } } if (result.states == null) { result.states.Add(currentState); Action empty = new Action(); empty.name = "empty"; empty.time = 5000; result.action = empty; result.probabilities.Add(100); } int index = 0; if (result.probabilities.Count > 1) { int randChoose = rand.Next(100); if (randChoose < result.probabilities[0]) { index = 0; } else if (randChoose < result.probabilities[0] + result.probabilities[1]) { index = 1; } else { if (result.states.Count > 2) { index = 2; } } } if (index >= result.states.Count) { index = 0; } Logging.Logger.AddInfo(myChar.name + ": " + result.action.ToString() + " proti " + enemy.GetCharacter().name + ", cost=" + lowestCost + ", efekt: " + index); myself.SetCoolDown(result.action.time); selectedAction = result.action; this.lastAction = selectedAction; //return result.states[index]; return(result.states[0]); }
/// <summary> /// apply actions on conflict state and by this generate followers of current confict state /// </summary> /// <param name="state"> current conflict state </param> /// <param name="character">character of npc, used for checking stats</param> /// <param name="actionType">action type, which says, what actions are available</param> /// <returns>List of state-probability pairs</returns> private List <StateProbPairs> Expand(ConflictState state, CharacterNPC character) { List <StateProbPairs> expanders = new List <StateProbPairs>(); //List<Action> actions = null; //switch (actionType) //{ // case ActionType.Attack: // actions = this.attackActions; // break; // case ActionType.Defense: // actions = this.defenseActions; // break; // default: // Logging.Logger.AddWarning("Spatny typ akce"); // return expanders; // //break; //} foreach (Action action in this.actions) { if (action.name == lastAction.name && action.name.StartsWith("Heal")) { break; } //TODO - spravit cooldownama StateProbPairs pairs = new StateProbPairs(); pairs.states = new List <ConflictState>(); pairs.probabilities = new List <int>(); ConflictState succesState; // = new ConflictState(); ConflictState noEffectState; // = new ConflictState(); ConflictState failState; // = new ConflictState(); succesState = state + action; //spell casted succesfull noEffectState = state; //casting has no effect, failState = state; // -action; //casting fail and harm caster failState.myHP -= action.enemyHpTaken; failState.myHP -= action.hpGot; int prob = action.probability; int noneProb = 100 - prob - failProb; int fail = failProb; //check and add to expanders if (CheckStats(character, ref succesState)) { pairs.states.Add(succesState); pairs.probabilities.Add(prob); if (action.probability != 100) { if (CheckStats(character, ref failState)) { pairs.states.Add(failState); pairs.probabilities.Add(fail); } //pairs.states.Add(noEffectState); //pairs.probabilities.Add(noneProb); } } pairs.action = action; if (pairs.states.Count > 0) { expanders.Add(pairs); } } return(expanders); }