Add Attack / AttackRequirement docs

This commit is contained in:
Gary Tierney
2016-01-29 22:12:13 +00:00
parent 27e06c304d
commit a7b4036deb
6 changed files with 63 additions and 24 deletions
+42 -5
View File
@@ -2,9 +2,40 @@ java_import 'org.apollo.cache.def.ItemDefinition'
java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.Graphic'
##
# The {@code BaseAttack} which all other {@code Attack}s derive from.
#
# Supports most general attacks by playing an {@code Animation} and an optional {@code Graphic}.
# Default options are:
# * a range of 1
# * no requirements
# * no graphic
class BaseAttack
attr_reader :requirements, :range, :speed
##
# The {@code AttackRequirement}s a {@code Player} must meet to use this attack.
attr_reader :requirements
##
# The maximum range this {@code Attack} can be executed from.
attr_reader :range
##
# How often this {@code Attack} can be executed in ticks.
attr_reader :speed
##
# Create a new {@code Attack} with the given properties.
#
# @param [Number] speed The minimum number of ticks to wait before this attack can be executed after
# a previous {@code Attack}.
# @param [Number] animation The {@code Animation} to play on the player when executing this {@code Attack}.
# @param [Hash] graphic The {@code Graphic} to play on the player when executing this {@code Attack}.
# @param [Number] range The maximum distance this {@code Attack} can be executed from.
# @param [Array] requirements The requirements that must be met to execute this {@code Attack}.
def initialize(speed:, animation:, graphic: nil, range: 1, requirements: [])
fail 'Attack speed must be a non-negative number' if speed < 0
fail 'Attack range must be a non-negative number' if range < 0
@@ -16,6 +47,12 @@ class BaseAttack
@requirements = requirements
end
##
# Execute this {@code Attack} and apply its effect.
#
# @param [Mob] source The attacker.
# @param [Mob] target The target.
def do(source, target)
source.play_animation(Animation.new(@animation))
@@ -86,9 +123,9 @@ class MagicAttack < BaseAttack
distance = source.position.get_distance(target.position)
damage_delay = (@projectile_type.delay + @projectile_type.speed + distance * 5) * 0.02857
schedule_damage!(source, target, rand(@damage), damage_delay) do
unless @hit_graphic.nil?
if @hit_graphic.is_a?(Hash)
target.play_graphic(Graphic.new(@hit_graphic[:id], @hit_graphic[:delay] || 0, @hit_graphic[:height] || 0))
@@ -96,10 +133,10 @@ class MagicAttack < BaseAttack
target.play_graphic(Graphic.new(@hit_graphic))
end
end
end
end
end
##
+9 -2
View File
@@ -3,6 +3,8 @@ java_import 'org.apollo.game.model.entity.EquipmentConstants'
java_import 'org.apollo.game.model.entity.Skill'
java_import 'org.apollo.cache.def.EquipmentDefinition'
##
# An {@code Exception} thrown by an {@code AttackRequirement} if a player doesn't atch its requirements.
class AttackRequirementException < Exception
attr_reader :message
@@ -11,11 +13,18 @@ class AttackRequirementException < Exception
end
end
##
# A requirement which is checked before an {@code Attack} is executed.
class AttackRequirement
##
# Verify that {@code _player} meets the requirements, throwing an AttackRequirementException with an appropriate
# message if not.
def validate(_player)
throw RuntimeError.new('validate! not implemented')
end
##
# Do any destructive actions (e.g., remove items) after all requirements for an {@code Attack} have been met.
def apply!(_player)
throw RuntimeError.new('apply not implemented')
end
@@ -44,7 +53,6 @@ class AttackRequirementDSL
def skill(skill, level:)
requirements << LevelRequirement.new(skill, level)
end
end
class SpecialEnergyRequirement < AttackRequirement
@@ -70,7 +78,6 @@ class SpecialEnergyRequirement < AttackRequirement
end
class LevelRequirement < AttackRequirement
SKILLS = {
:magic => Skill::MAGIC
}
+7 -6
View File
@@ -20,24 +20,25 @@ end
on :message, :magic_on_mob do |player, message|
target = $world.npc_repository.get(message.index)
next unless SPELLBOOKS.has_key? message.interface_id
player_combat_state = player.get_combat_state
player_combat_state.target = target
spellbook = spellbook_for(message.interface_id)
spellbook = SPELLBOOKS[message.interface_id]
spell = spell_for(spellbook, message.spell_id)
player_combat_state.queue_attack(spell.attack)
player.walking_queue.clear
player.start_action CombatAction.new(player)
magic_attack = MagicAttack.new(spell)
player_combat_state.queue_attack(magic_attack)
player.start_action CombatAction.new(player, true)
end
on :message, :player_action do |player, message|
end
## TODO: another way of handling this
schedule 0 do |_task|
$world.player_repository.each { |player| player.attack_timer = player.attack_timer + 1 }
$world.npc_repository.each { |npc| npc.attack_timer = npc.attack_timer + 1 }
-11
View File
@@ -1,11 +0,0 @@
SPELLBOOKS = {}
def create_spellbook(identifier, interface_id:)
SPELLBOOKS[interface_id] = identifier
end
def spellbook_for(interface_id)
fail "Could not find spellbook for #{interface_id}" unless SPELLBOOKS.has_key?(interface_id)
return SPELLBOOKS[interface_id]
end
+5
View File
@@ -1,2 +1,7 @@
SPELLBOOKS = {}
def create_spellbook(identifier, interface_id:)
SPELLBOOKS[interface_id] = identifier
end
create_spellbook :modern, interface_id: 192