//The main function! This EXACT coroutine will be executed, even across frames. //See GameAction.cs for more information on how this function should work! public override IEnumerator TakeAction() { if (target) { GameAction act = new PathfindAction(target.location); act.Setup(caller); while (act.action.MoveNext()) { yield return(act.action.Current); } } else { Debug.Log("Console (player only): Can't auto-fight with no enemies in sight!"); yield break; } }
//The main loop for monster AI! This assumes public override IEnumerator DetermineAction() { if (monster.view == null) { Debug.LogError("Monster did not have a view available! If this happened during real gameplay, we have a problem. Eating its turn to be safe."); monster.UpdateLOS(); nextAction = new WaitAction(); yield break; } monster.view.CollectEntities(Map.current); List <Monster> enemies = monster.view.visibleMonsters.Where(x => (x.faction & monster.faction) == 0).ToList(); if (enemies.Count == 0) { //Standard behavior //TODO: If someone is offering actions, look at their action and maybe take it //Else, try to go exploring! //Else, just wait? Debug.Log("Monster is just waiting!"); nextAction = new WaitAction(); yield break; } else { //We're majorly in combat! //Options //0 - Flee (Default) //1 - Fight //2 - Spell float flee = fleeQuery.Evaluate(monster, monster.view.visibleMonsters, null, null); float approach = approachQuery.Evaluate(monster, monster.view.visibleMonsters, null, null); (int spellIndex, float spellValue) = (-1, -1); if (monster.abilities) { (spellIndex, spellValue) = monster.abilities.GetBestAbility(); } //TODO: Determine if any items would be a good fit List <int> bestChoice = new List <int> { 0 }; float bestVal = flee; //Fighting check if (approach > bestVal) { bestChoice.Clear(); bestChoice.Add(1); bestVal = approach; } if (approach == bestVal) { bestChoice.Add(1); } //Ability check if (spellValue > bestVal) { bestChoice.Clear(); bestChoice.Add(2); bestVal = spellValue; } if (spellValue == bestVal) { bestChoice.Add(2); } int choice = bestChoice[Random.Range(0, bestChoice.Count)]; switch (bestChoice[Random.Range(0, bestChoice.Count)]) { case 0: Debug.Log("Should flee!!"); nextAction = new FleeAction(); break; case 1: Debug.Log("Should Attack!!"); enemies = enemies.OrderBy(x => Vector2Int.Distance(monster.location, x.location)).ToList(); nextAction = new PathfindAction(enemies[0].location); break; case 2: Debug.Log($"Should use spell {monster.abilities[spellIndex].displayName}"); nextAction = new WaitAction(); break; default: Debug.LogError($"Can't make choice {choice}, so waiting instead"); nextAction = new WaitAction(); break; } } }