AI.gd 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. extends Object
  2. class_name AI
  3. #
  4. static func SetState(agent : AIAgent, state : AICommons.State, force : bool = false):
  5. var newState : AICommons.State = state if force else AICommons.GetTransition(agent.aiState, state)
  6. if agent.aiState != newState:
  7. agent.aiState = newState
  8. if AICommons.IsActionInProgress(agent):
  9. Callback.ClearTimer(agent.actionTimer)
  10. if AICommons.IsAgentMoving(agent):
  11. if agent.skillSelected:
  12. agent.skillSelected = null
  13. else:
  14. agent.ResetNav()
  15. if agent.agent:
  16. agent.agent.avoidance_enabled = agent.aiState == AICommons.State.ATTACK
  17. static func Reset(agent : AIAgent):
  18. SetState(agent, AICommons.State.IDLE, true)
  19. agent.ResetNav()
  20. Callback.StartTimer(agent.aiTimer, agent.aiRefreshDelay, Refresh.bind(agent))
  21. static func Stop(agent : AIAgent):
  22. SetState(agent, AICommons.State.HALT)
  23. static func Refresh(agent : AIAgent):
  24. if not ActorCommons.IsAlive(agent) or not WorldAgent.GetInstanceFromAgent(agent):
  25. Stop(agent)
  26. else:
  27. if AICommons.HasExpiredNodeGoal(agent):
  28. Reset(agent)
  29. HandleBehaviour(agent)
  30. match agent.aiState:
  31. AICommons.State.IDLE:
  32. StateIdle(agent)
  33. AICommons.State.WALK:
  34. StateWalk(agent)
  35. AICommons.State.ATTACK:
  36. StateAttack(agent)
  37. AICommons.State.HALT:
  38. if agent.agent:
  39. agent.agent.avoidance_layers = 0
  40. Callback.ClearTimer(agent.aiTimer)
  41. return
  42. _:
  43. assert(false, "AI state not handled")
  44. Callback.LoopTimer(agent.aiTimer, AICommons.MinRefreshDelay if agent.aiState == AICommons.State.ATTACK else agent.aiRefreshDelay)
  45. static func HandleBehaviour(agent : AIAgent):
  46. var handled : bool = false
  47. # Check if should idle
  48. if not handled and agent.aiBehaviour & AICommons.Behaviour.SPAWNER:
  49. handled = AICommons.ApplySpawnerBehaviour(agent)
  50. if not handled and agent.aiBehaviour & AICommons.Behaviour.IMMOBILE:
  51. handled = AICommons.ApplyImmobileBehaviour(agent)
  52. # Check if should attack, either one of those
  53. if not handled and agent.aiBehaviour & AICommons.Behaviour.PACIFIST:
  54. handled = AICommons.ApplyPacifistBehaviour(agent)
  55. elif not handled and agent.aiBehaviour & AICommons.Behaviour.NEUTRAL:
  56. handled = AICommons.ApplyNeutralBehaviour(agent)
  57. elif not handled and agent.aiBehaviour & AICommons.Behaviour.AGGRESSIVE:
  58. handled = AICommons.ApplyAggressiveBehaviour(agent)
  59. # Check if should walk
  60. if not handled and agent.aiBehaviour & AICommons.Behaviour.STEAL:
  61. handled = AICommons.ApplyStealBehaviour(agent)
  62. if not handled and agent.aiBehaviour & AICommons.Behaviour.FOLLOWER:
  63. handled = AICommons.ApplyFollowerBehaviour(agent)
  64. #
  65. static func StateIdle(agent : AIAgent):
  66. if not AICommons.IsActionInProgress(agent):
  67. if AICommons.CanWalk(agent):
  68. Callback.StartTimer(agent.actionTimer, AICommons.GetWalkTimer(), AI.ToWalk.bind(agent))
  69. static func StateWalk(agent : AIAgent):
  70. if not AICommons.IsAgentMoving(agent) or AICommons.IsStuck(agent):
  71. Reset(agent)
  72. static func StateAttack(agent : AIAgent):
  73. var target : BaseAgent = agent.GetMostValuableAttacker()
  74. if not target:
  75. Reset(agent)
  76. elif not AICommons.IsActionInProgress(agent):
  77. agent.skillSelected = AICommons.GetRandomSkill(agent)
  78. if not agent.skillSelected:
  79. if AICommons.CanWalk(agent):
  80. ToFlee(agent, target)
  81. elif SkillCommons.IsAttackable(agent, target, agent.skillSelected):
  82. ToAttack(agent, target)
  83. elif target:
  84. if AICommons.CanWalk(agent):
  85. ToChase(agent, target)
  86. else:
  87. Reset(agent)
  88. else: # Has target and is moving toward a Node2D goal
  89. if not ActorCommons.IsAlive(target) or (AICommons.IsAgentMoving(agent) and agent.nodeGoal == null):
  90. Reset(agent)
  91. # Could be delayed, always check if agent is inside a map
  92. static func ToWalk(agent : AIAgent):
  93. var map : WorldMap = WorldAgent.GetMapFromAgent(agent)
  94. if map:
  95. SetState(agent, AICommons.State.WALK, true)
  96. var position : Vector2i = agent.position
  97. if agent.leader != null:
  98. position = WorldNavigation.GetRandomPositionAABB(map, agent.leader.position, AICommons.MaxOffsetVector)
  99. agent.SetNodeGoal(agent.leader, position)
  100. else:
  101. # Check if agent is within its spawn wandering zone
  102. var deltaPosition: Vector2 = agent.position - Vector2(agent.spawnInfo.spawn_position)
  103. if agent.spawnInfo.is_global or \
  104. abs(deltaPosition.x) <= agent.spawnInfo.spawn_offset.x and abs(deltaPosition.y) <= agent.spawnInfo.spawn_offset.y or \
  105. (deltaPosition - Vector2(agent.spawnInfo.spawn_offset)).length_squared() <= AICommons.WanderDistanceSquared:
  106. position = WorldNavigation.GetRandomPositionAABB(map, agent.position, AICommons.MaxOffsetVector)
  107. else:
  108. position = WorldNavigation.GetRandomPositionAABB(map, agent.spawnInfo.spawn_position, agent.spawnInfo.spawn_offset)
  109. agent.SetNodeGoal(agent, position)
  110. var walkSpeed : int = randi_range(agent.minWanderingSpeed, agent.maxWanderingSpeed)
  111. agent.currentWalkSpeed = Vector2(walkSpeed, walkSpeed)
  112. Callback.OneShotCallback(agent.agent.navigation_finished, AI.SetState, [agent, AICommons.State.IDLE])
  113. static func ToAttack(agent : AIAgent, target : BaseAgent):
  114. if AICommons.IsAgentMoving(agent):
  115. agent.ResetNav()
  116. if WorldAgent.GetMapFromAgent(agent):
  117. Skill.Cast(agent, target, agent.skillSelected)
  118. static func ToChase(agent : AIAgent, target : BaseAgent):
  119. var map : WorldMap = WorldAgent.GetMapFromAgent(agent)
  120. if map and SkillCommons.IsSameMap(agent, target):
  121. agent.SetNodeGoal(target, target.position)
  122. Callback.OneShotCallback(agent.agent.navigation_finished, AI.Refresh, [agent])
  123. agent.currentWalkSpeed = Vector2(agent.stat.current.walkSpeed, agent.stat.current.walkSpeed)
  124. static func ToFlee(agent : AIAgent, target : BaseAgent):
  125. var map : WorldMap = WorldAgent.GetMapFromAgent(agent)
  126. if map and SkillCommons.IsSameMap(agent, target):
  127. var fleePosition : Vector2 = agent.position - agent.position.direction_to(target.position) * AICommons.FleeDistance
  128. SetState(agent, AICommons.State.WALK, true)
  129. agent.SetNodeGoal(target, fleePosition)
  130. Callback.OneShotCallback(agent.agent.navigation_finished, AI.SetState, [agent, AICommons.State.IDLE])