Build a framework for a maintainable combat plugin

* Uses a hierarchy of WeaponClasses -> Weapons for performing attacks,
  with WeaponClass having a set of styles and associated Attacks for
  those styles. Weapons and their classes are built with an easy to use
  and clean DSL.

* Adds a BonusContainer mixin, so that Equipment, Weapons, and
  WeaponClasses can all have their own set of bonuses which apply to the
  player.

* Allows attacks to be queued to the Mobs CombatState instance from
  external code, allowing e.g., NPCs or auto-cast to queue attacks to be
  executed.
This commit is contained in:
Gary Tierney
2016-02-29 21:24:34 +00:00
parent 7731eedf3d
commit 348e5cc8dc
21 changed files with 895 additions and 80 deletions
+88
View File
@@ -0,0 +1,88 @@
java_import 'org.apollo.cache.def.ItemDefinition'
java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.Graphic'
class BaseAttack
attr_reader :requirements, :range
def initialize(animation, graphic = nil, range = 1, requirements = [])
@animation = animation
@graphic = graphic
@range = range
@requirements = requirements
end
def do(source, target)
source.play_animation(Animation.new(@animation))
unless @graphic.nil?
if @graphic.is_a?(Hash)
source.play_graphic(Graphic.new(@graphic[:id], @graphic[:delay] || 0, @graphic[:height] | 0))
else
source.play_graphic(Graphic.new(@graphic))
end
end
apply(source, target)
end
def apply(source, target)
raise "BaseAttack#apply unimplemented"
end
def damage!(source, target, amount, delay = 0)
schedule delay do |task|
task.stop && return if source.dead or target.dead
target_combat_state = get_combat_state target
target_hitpoints = target.skill_set.get_skill(Skill::HITPOINTS).get_current_level
amount = target_hitpoints if target_hitpoints < amount
type = amount > 0 ? 1 : 0
target.play_animation(Animation.new(424)) unless target_combat_state.state == :attacking
target.damage(amount, type, false)
task.stop
end
end
end
class ProcAttack < BaseAttack
def initialize(block, animation:, graphic:, range: 1, requirements: [])
super(animation, graphic, range, requirements)
@block = block
end
def apply(source, target)
self.instance_exec(source, target, &@block)
end
end
class RangedAttack < BaseAttack
def initialize(animation:, graphic:, requirements: [])
end
def calculate_delay(source, target)
end
def apply(source, target)
end
def projectile!(source, target, projectile_id)
end
end
class Attack < BaseAttack
def initialize(animation:, graphic: nil, range: 1, requirements: [])
super(animation, graphic, range, requirements)
end
def apply(source, target)
damage! source, target, CombatUtil::calculate_hit(source, target)
end
end