Move next_attack logic to CombatState

* Moves the decision of what attack is used next to CombatState and
  defers selecting the attack until the player is actually ready to hit
  their target for damage.

* Adds a distance check so combat is only initiated within the correct
  range. If the player isn't close enough to their target, they will run
  towards it and check every tick if they're close enough to make an
  attack.
This commit is contained in:
Gary Tierney
2016-02-29 22:21:21 +00:00
parent 064f22d2e0
commit 17e8d02886
2 changed files with 51 additions and 16 deletions
+33 -15
View File
@@ -50,7 +50,19 @@ class CombatAction < Action
end end
def update_idle def update_idle
if @combat_state.queued_attacks.empty? and @combat_state.supports_weapon next_attack = @combat_state.next_attack true
current_distance = mob.position.get_distance @combat_state.target.position
if current_distance > next_attack.range
@combat_state.state = :chasing
mob.follow @combat_state.target, next_attack.range
set_delay 0
return
end
if @combat_state.supports_weapon
weapon = EquipmentUtil.equipped_weapon mob weapon = EquipmentUtil.equipped_weapon mob
weapon_class = weapon.weapon_class weapon_class = weapon.weapon_class
combat_style = weapon_class.style_at mob.combat_style combat_style = weapon_class.style_at mob.combat_style
@@ -62,16 +74,7 @@ class CombatAction < Action
mob.attacking = true mob.attacking = true
end end
if mob.using_special and weapon.special_attack?
@combat_state.next_attack = weapon.special_attack
else
@combat_state.next_attack = weapon_class.attack(combat_style)
end
@combat_state.state = :attacking @combat_state.state = :attacking
elsif @combat_state.queued_attacks.size > 0
@combat_state.next_attack = @combat_state.queued_attacks.pop
@combat_state.state = :attacking
else else
stop stop
@combat_state.reset @combat_state.reset
@@ -79,20 +82,35 @@ class CombatAction < Action
end end
def update_attacking def update_attacking
raise RuntimeError.new('no attack when in :attacking state') if @combat_state.next_attack.nil?
begin begin
@combat_state.next_attack.do(mob, @combat_state.target) next_attack = @combat_state.next_attack
next_attack.requirements.each do |requirement|
requirement.validate! mob
end
@combat_state.state = :idle next_attack.requirements.each do |requirement|
set_delay 0 requirement.apply mob
end
next_attack.do(mob, @combat_state.target)
rescue AttackRequirementException => e rescue AttackRequirementException => e
mob.send_message e.message mob.send_message e.message
ensure
@combat_state.state = :idle
set_delay 0
end end
end end
def update_chasing def update_chasing
next_attack = @combat_state.next_attack true
current_distance = mob.position.get_distance @combat_state.target.position
if current_distance <= next_attack.range
@combat_state.state = :attacking
mob.following = -1
set_delay 0
end
end end
def stop def stop
+18 -1
View File
@@ -11,7 +11,7 @@ end
private private
class CombatState class CombatState
attr_accessor :state, :next_attack attr_accessor :state
attr_reader :queued_attacks, :supports_weapon attr_reader :queued_attacks, :supports_weapon
def initialize(mob, supports_weapon = true) def initialize(mob, supports_weapon = true)
@@ -41,6 +41,23 @@ class CombatState
def queue_attack(attack) def queue_attack(attack)
@queued_attacks.push(attack) @queued_attacks.push(attack)
end end
def next_attack(peek = false)
if @queued_attacks.size > 0
peek ? @queued_attacks.first : @queued_attacks.pop
else
weapon = EquipmentUtil.equipped_weapon @mob
if @mob.using_special and weapon.special_attack?
weapon.special_attack
else
weapon_class = weapon.weapon_class
combat_style = weapon_class.style_at @mob.combat_style
weapon_class.attack combat_style
end
end
end
end end
MOB_COMBAT_STATE_CACHE = { MOB_COMBAT_STATE_CACHE = {