Here is my Enemy AI core for an ABS. Since I can't right now, maybe Sthratoff will take the time to explain it a little bit. It's not really hard, it just gets more complex with more available actions and states.
module Enemy_AI
# bosses have a special AI
BOSS_IDS = []
class Enemy_AI
# setting all accessable variables
attr_accessor :state
attr_accessor :in_action
attr_accessor :attacked
attr_accessor :find_x
attr_accessor :find_y
attr_accessor :dmg
attr_accessor :damage
#----------------------------------------------------------------------------
# AI initialization
#----------------------------------------------------------------------------
def initialize(maxhp, eva)
# enemy's max HP
@maxhp = maxhp
# how likely is the enemy to flee
@coward = eva.to_f
# possible AI states:
# 0 - idle/move
# 1 - move
# 2 - attack
# 3 - skill
# 4 - defend
# 5 - run away
# 6 - exception
# 7 - memorized position
# 8 - disappearing
# 9 - in action
@state = 0
# collection of last damages to test if the player is stronger
@dmg = []
# damage sprite
@damage = nil
# an active enemy attacks with full power
@active = false
# memory flag
@memory = false
# attack shock count
@attacked = 0
# attack busy count
@in_action = 0
# fear shock count
@fear = 0
# last x and y of the player when lost out of sight
@find_x = -1
@find_y = -1
end
#----------------------------------------------------------------------------
# in_range?(x, y, dir)
# x - x-coordinate
# y - y-coordinate
# dir - facing direction
# defines the enemy's behaviour depending on the fact if the player is
# inside a specific range
#----------------------------------------------------------------------------
def in_range?(x, y, dir, enemy)
if @attacked > 0 # if enemy in attack shock/attacked
# decrease shock count
@attacked -= 1
# cancel the attack
@in_action = @attacked
# set state
@state = 6
# return speed
return 5
end
if @in_action > 0 # if enemy in attack shock/attacked
# decrease shock count
@in_action -= 1
# set state
@state = @state == 4 ? 4 : 9
# return speed
return 4
end
if judge or @fear > 0 # if enemy should flee or already fleeing
# decrease the fear count
@fear -= 1
# set state
@state = 5
# return speed
return 4
end
# calculates the distance
d = Math.sqrt((($game_player.x+4)/8-x)**2 + (($game_player.y+4)/8-y)**2)
# player was seen/heard
perception = (can_precept_player?(x, y, dir) or $game_player.in_action > 0)
# if player is in range of 5 squares and seen/heard or percepted or
# already memorized by the enemy
if d <= 5 and (perception or @memory)
# player sighted, remembers that
@memory = true
# set the last coordinates of the player
@find_x = $game_player.x
@find_y = $game_player.y
if d <= 1 # player in range, attack him
action = what_to_do?(enemy)
if action == []
# set state
@state = 2
# return speed
return 4
else
if action[0] == 0
if action[1] == 0
# set state
@state = 2
# return speed
return 4
else
# set state
@state = 4
# return speed
return 4
end
else
# set state
@state = 3
# return speed
return [4, action[2]]
end
end
end
# set state
@state = 1
# return speed
return 4
elsif @memory # has lost player out of sight, but remembers last position
# difference between coordinates
dx = x - (@find_x+4)/8
dy = y - (@find_y+4)/8
# if the enemy has reached the desired x and y
if dx.abs <= 1 and dy.abs <= 1
# player lost out of sight
@memory = false
# set idle state
@state = 0
# return speed
return 3
end
# set state
@state = 7
# return speed
return 4
else # otherwise player is not in sight, be "idle"
# set idle state
@state = 0
# return speed
return 3
end
# set state either attack, skill or defend
#@state = rand(3) + 2
# return speed
#return 4
end
#----------------------------------------------------------------------------
# judge
# defines if the enemy has lost enough energy in an enough short period of
# time to flee
#----------------------------------------------------------------------------
def judge
result = (@dmg.sum * 100 / @maxhp > 100.0 - @coward)
@fear = ((@coward.to_f ** (1/4) + 1) * 20).to_i if result
return result
end
#----------------------------------------------------------------------------
# refresh
# removes the least recent damage accumulation, used by judge
#----------------------------------------------------------------------------
def refresh
@dmg.shift unless @dmg.size == 0
end
#----------------------------------------------------------------------------
# can_precept_player?(x, y, dir)
# x - x-coordinate
# y - y-coordinate
# dir - facing direction
# defines if the player can be heard or seen
#----------------------------------------------------------------------------
def can_precept_player?(x, y, dir)
# calculate differences of x and y
dx = x - ($game_player.x+4)/8.0
dy = y - ($game_player.y+4)/8.0
# check facing direction and return true if the player is inside the
# seeing/hearing spectrum of the enemy
case dir
when 2
return true if dy < 0 and (dx.abs < dy.abs or dx.abs <= 2 and dy.abs <= 2)
when 4
return true if dx < 0 and (dx.abs > dy.abs or dx.abs <= 2 and dy.abs <= 2)
when 6
return true if dx > 0 and (dx.abs > dy.abs or dx.abs <= 2 and dy.abs <= 2)
when 8
return true if dy > 0 and (dx.abs < dy.abs or dx.abs <= 2 and dy.abs <= 2)
end
return false
end
#----------------------------------------------------------------------------
# get_a_effect
# processing of the skill priority
#----------------------------------------------------------------------------
def what_to_do?(enemy)
return [] unless enemy.movable?
available_actions = []
rating_max = 0
for action in enemy.actions
next if enemy.hp * 100.0 / enemy.maxhp > action.condition_hp
next if $game_party.max_level < action.condition_level
switch_id = action.condition_switch_id
next if switch_id > 0 and $game_switches[switch_id] == false
available_actions.push(action)
rating_max = action.rating if action.rating > rating_max
end
ratings_total = 0
for action in available_actions
if action.rating > rating_max - 3
ratings_total += action.rating - (rating_max - 3)
end
end
if ratings_total > 0
value = rand(ratings_total)
for action in available_actions
if action.rating > rating_max - 3
if value < action.rating - (rating_max - 3)
kind = action.kind
basic = action.basic
skill_id = action.skill_id
return [kind, basic, skill_id]
else
value -= action.rating - (rating_max - 3)
end
end
end
end
return []
end
end
end