using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace BossRoom.Server { /// /// Handles enemy AI. Contains AIStateLogics that handle some of the details, /// and has various utility functions that are called by those AIStateLogics /// public class AIBrain { private enum AIStateType { ATTACK, //WANDER, IDLE, } private ServerCharacter m_serverCharacter; private ActionPlayer m_actionPlayer; private AIStateType m_currentState; private Dictionary m_logics; private List m_hatedEnemies; public AIBrain(ServerCharacter me, ActionPlayer myActionPlayer) { m_serverCharacter = me; m_actionPlayer = myActionPlayer; m_logics = new Dictionary { [ AIStateType.IDLE ] = new IdleAIState(this), //[ AIStateType.WANDER ] = new WanderAIState(this), // not written yet [ AIStateType.ATTACK ] = new AttackAIState(this, m_actionPlayer), }; m_hatedEnemies = new List(); m_currentState = AIStateType.IDLE; } /// /// Should be called by the AIBrain's owner each Update() /// public void Update() { AIStateType newState = FindBestEligibleAIState(); if (m_currentState != newState) { m_logics[ newState ].Initialize(); } m_currentState = newState; m_logics[ m_currentState ].Update(); } private AIStateType FindBestEligibleAIState() { // for now we assume the AI states are in order of appropriateness, // which may be nonsensical when there are more states foreach (AIStateType type in Enum.GetValues(typeof(AIStateType))) { if (m_logics[ type ].IsEligible()) { return type; } } Debug.LogError("No AI states are valid!?!"); return AIStateType.IDLE; } #region Functions for AIStateLogics /// /// Returns true if it be appropriate for us to murder this character, starting right now! /// public bool IsAppropriateFoe(ServerCharacter potentialFoe) { if (potentialFoe == null || potentialFoe.IsNPC) { return false; } // FIXME: check for dead! // Also, we could use NavMesh.Raycast() to see if we have line of sight to foe? return true; } /// /// Notify the AIBrain that we should consider this character an enemy. /// /// public void Hate(ServerCharacter character) { if (!m_hatedEnemies.Contains(character)) { m_hatedEnemies.Add(character); } } /// /// Return the raw list of hated enemies -- treat as read-only! /// public List GetHatedEnemies() { // first we clean the list -- remove any enemies that have disappeared (became null), are dead, etc. m_hatedEnemies.RemoveAll(enemy => !IsAppropriateFoe(enemy)); return m_hatedEnemies; } /// /// Retrieve info about who we are. Treat as read-only! /// /// public ServerCharacter GetMyServerCharacter() { return m_serverCharacter; } #endregion } }