mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-04 00:38:11 +00:00
Add ranged combat support
* Clean up the CombatAction and Attack code to make it easier to use for range. * Add collision detection to the distance checks before attacking in the CombatAction. * Create a Ruby DSL for defining projectile types and fix the ProjectileUpdateOperation so it uses the correct position offset. * Fix the packet structure of the HintIconMessageEncoder.
This commit is contained in:
@@ -4,122 +4,169 @@ COMBAT_STYLES = [
|
||||
:defensive,
|
||||
:controlled,
|
||||
:alt_aggressive,
|
||||
:accurate_ranged,
|
||||
:rapid,
|
||||
:long_range
|
||||
]
|
||||
|
||||
MELEE_COMBAT_STYLES = [
|
||||
:accurate,
|
||||
:aggressive,
|
||||
:alt_aggressive,
|
||||
:controlled,
|
||||
:defensive
|
||||
]
|
||||
|
||||
RANGE_COMBAT_STYLES = [
|
||||
:accurate_ranged,
|
||||
:rapid,
|
||||
:long_range
|
||||
]
|
||||
##
|
||||
# A model for a weapon class, which contains the necessary inform
|
||||
|
||||
class WeaponClass
|
||||
attr_reader :widget, :name, :special_bar_button, :special_bar_config
|
||||
##
|
||||
# Allow this class to set combat bonuses.
|
||||
|
||||
include Combat::BonusContainer
|
||||
|
||||
def initialize(name, widget)
|
||||
@name = name
|
||||
@widget = widget
|
||||
@styles = {}
|
||||
@style_attacks = {}
|
||||
@style_offsets = []
|
||||
@animations = {}
|
||||
##
|
||||
# The widget which is displayed on the combat tab when this weapon class
|
||||
# is in use.
|
||||
|
||||
attr_reader :widget
|
||||
|
||||
##
|
||||
# A unique identifier for this class.
|
||||
|
||||
attr_reader :name
|
||||
|
||||
##
|
||||
# The id of the special bar button for this weapon class, if applicable.
|
||||
|
||||
attr_reader :special_bar_button
|
||||
|
||||
##
|
||||
# The id of the widget config used to hide this weapon classes special bar, if applicable.
|
||||
|
||||
attr_reader :special_bar_config
|
||||
|
||||
##
|
||||
# Create a new WeaponClass with the given name and specified widget id.
|
||||
#
|
||||
# @param [Symbol] name The unique name to give this weapon class.
|
||||
# @param [Number] widget The id of the widget associated with this weapon class.
|
||||
|
||||
def initialize(name, widget, type)
|
||||
@name = name
|
||||
@widget = widget
|
||||
@type = type
|
||||
@styles = {}
|
||||
@defaults = {}
|
||||
@animations = {}
|
||||
end
|
||||
|
||||
def add_style(style, button: nil, attack_type: nil, speed: nil, animation: nil, block_animation: nil, range: 1)
|
||||
raise 'Invalid combat style given' unless COMBAT_STYLES.include? style
|
||||
##
|
||||
# Set default properties which are used for styles which don't have
|
||||
# those properties defined.
|
||||
#
|
||||
# @param [Hash] props
|
||||
# * :attack_type [Symbol] The default attack type for styles in this class.
|
||||
# * :speed [Number] The default attack speed for styles in this class.
|
||||
# * :animation [Number] The default attack animation id for styles in this class.
|
||||
# * :block_animation [Number] The default block animation id for styles in this class.
|
||||
# * :range [Number] The default attack range for styles in this class.
|
||||
|
||||
@styles[style] = {
|
||||
:attack_type => attack_type,
|
||||
:speed => speed,
|
||||
:animation => animation,
|
||||
:block_animation => block_animation,
|
||||
:range => range,
|
||||
:button => button == nil ? @styles.size + 1 : button
|
||||
}
|
||||
|
||||
@style_offsets.push style
|
||||
|
||||
if MELEE_COMBAT_STYLES.include? style
|
||||
@style_attacks[style] = Attack.new(animation: animation)
|
||||
def defaults(props)
|
||||
@defaults = props
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new {@link CombatStyle} to to this class.
|
||||
#
|
||||
# @param [Symbol] style The name of the style, one of {@link COMBAT_STYLES}.
|
||||
# @param [Hash] properties
|
||||
# * :button [Number] The id of the button which activates this style.
|
||||
# * :attack_type [Symbol] The attack type for this style.
|
||||
# * :speed [Number] The attack speed for this style.
|
||||
# * :animation [Number] The attack animation id for this style.
|
||||
# * :graphic [Hash|Number] The id, or a hash specifying height and id for the graphic for this style.
|
||||
# * :requirements [Array] An array of [AttackRequirement] objects to be applied to this styles attack.
|
||||
# * :block_animation [Number] The block animation id for this style.
|
||||
# * :range [Number] The attack range for this style.
|
||||
#
|
||||
# @param [Proc] block An optional block which is called in the context of an AttackDSL if present, to create an attack for
|
||||
# this style.
|
||||
|
||||
def style(style, properties = {}, &block)
|
||||
fail 'Invalid combat style given' unless COMBAT_STYLES.include? style
|
||||
|
||||
properties = @defaults.merge properties
|
||||
|
||||
## The config ID used to set the active combat style, typically 0-3. TODO: does this always work?
|
||||
config = @styles.size
|
||||
button, attack_type, block_animation = properties[:button], properties[:attack_type], properties[:block_animation]
|
||||
|
||||
@styles[style] = CombatStyle.new(button, config, attack_type, block_animation)
|
||||
|
||||
if block_given?
|
||||
attack_dsl = AttackDSL.new
|
||||
attack_dsl.speed = properties[:speed]
|
||||
attack_dsl.graphic = properties[:graphic]
|
||||
attack_dsl.animation = properties[:animation]
|
||||
attack_dsl.range = properties[:range]
|
||||
properties[:requirements].each {|requirement| attack_dsl.add_requirement requirement }
|
||||
attack_dsl.instance_eval &block
|
||||
|
||||
@styles[style].attack = attack_dsl.to_attack
|
||||
end
|
||||
|
||||
return unless @styles[style].attack.nil?
|
||||
|
||||
## Get rid of any properties which aren't included in the keyword argument list
|
||||
properties.delete_if {|key| ![:speed, :animation, :range, :requirements, :graphic].include? key }
|
||||
|
||||
if @type == :melee
|
||||
@styles[style].attack = Attack.new(properties)
|
||||
elsif @type == :ranged
|
||||
@styles[style].attack = RangedAttack.new(properties)
|
||||
end
|
||||
end
|
||||
|
||||
def attack(style)
|
||||
@style_attacks[style]
|
||||
##
|
||||
# Get the currently selected combat style in this class for the given mob.
|
||||
# @param [Mob] mob
|
||||
# @return [CombatStyle]
|
||||
|
||||
def selected_style(mob)
|
||||
style = @styles.find { |_key, value| value.button == mob.combat_style }
|
||||
|
||||
style = @styles.min_by { |_key, value| value.button } if style.nil?
|
||||
|
||||
# We want the last element because Hash#find returns [key, value]
|
||||
style.last
|
||||
end
|
||||
|
||||
def attack_type(style)
|
||||
@styles[style][:attack_type]
|
||||
end
|
||||
##
|
||||
# Get the animation id for the given animation type.
|
||||
|
||||
def block_animation(style)
|
||||
@styles[style][:block_animation]
|
||||
end
|
||||
|
||||
def button(style)
|
||||
@styles[style][:button]
|
||||
end
|
||||
|
||||
def config(style)
|
||||
@style_offsets.find_index {|v| v == style }
|
||||
end
|
||||
|
||||
def other_animation(type)
|
||||
def animation(type)
|
||||
@animations[type]
|
||||
end
|
||||
|
||||
def speed(style)
|
||||
@styles[style][:speed] || default_speed
|
||||
end
|
||||
|
||||
def style_at(button)
|
||||
selected_style = @styles.select { |key, hash| hash[:button] == button }.keys[0]
|
||||
|
||||
if selected_style == nil
|
||||
selected_style = @styles.min_by { |key, hash| hash[:button] }.first
|
||||
end
|
||||
|
||||
selected_style
|
||||
end
|
||||
|
||||
def default_speed(speed = nil)
|
||||
unless speed.nil?
|
||||
@default_speed = speed
|
||||
end
|
||||
|
||||
@default_speed
|
||||
end
|
||||
##
|
||||
# Set the widget config and button for this classes special attack bar.
|
||||
|
||||
def special_bar(config, button)
|
||||
@special_bar_config = config
|
||||
@special_bar_button = button
|
||||
end
|
||||
|
||||
##
|
||||
# Check if this weapon class supports a special attack bar.
|
||||
|
||||
def special_bar?
|
||||
!@special_bar_button.nil? and !@special_bar_config.nil?
|
||||
!@special_bar_button.nil? && !@special_bar_config.nil?
|
||||
end
|
||||
|
||||
##
|
||||
|
||||
def animations(stand: nil, walk: nil, run: nil, idle_turn: nil, turn_around: nil, turn_left: nil, turn_right: nil)
|
||||
@animations = {
|
||||
:stand => stand,
|
||||
:walk => walk,
|
||||
:run => run,
|
||||
:idle_turn => idle_turn,
|
||||
:turn_around => turn_around,
|
||||
:turn_left => turn_left,
|
||||
:turn_right => turn_right
|
||||
stand: stand,
|
||||
walk: walk,
|
||||
run: run,
|
||||
idle_turn: idle_turn,
|
||||
turn_around: turn_around,
|
||||
turn_left: turn_left,
|
||||
turn_right: turn_right
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -127,8 +174,8 @@ end
|
||||
WEAPON_CLASSES = {}
|
||||
WEAPON_CLASS_INTERFACE_MAP = {}
|
||||
|
||||
def create_weapon_class(name, widget:, &block)
|
||||
weapon_class = WeaponClass.new(name, widget)
|
||||
def create_weapon_class(name, widget:, type: :melee, &block)
|
||||
weapon_class = WeaponClass.new(name, widget, type)
|
||||
weapon_class.instance_eval &block
|
||||
|
||||
WEAPON_CLASSES[name.to_sym] = weapon_class
|
||||
|
||||
Reference in New Issue
Block a user