diff --git a/data/plugins/areas/actions.rb b/data/plugins/areas/actions.rb index e72f42f4..58eab91e 100644 --- a/data/plugins/areas/actions.rb +++ b/data/plugins/areas/actions.rb @@ -3,8 +3,20 @@ require 'java' java_import 'org.apollo.game.message.impl.DisplayCrossbonesMessage' java_import 'org.apollo.game.model.entity.Player' + + +# Registers an area action. +def area_action(name, &block) + AREA_ACTIONS[name] = action = AreaAction.new + action.instance_eval(&block) +end + + AREA_ACTIONS = {} + +private + # An action that is called when a player enters or exits an area. class AreaAction @@ -38,31 +50,4 @@ class AreaAction @on_exit.call(player) unless @on_exit.nil? end -end - -# Registers an area action. -def area_action(name, &block) - AREA_ACTIONS[name] = action = AreaAction.new - action.instance_eval(&block) -end - -# Defines the pvp area action. -area_action :pvp do - on_entry { |player| player.in_pvp = true } - on_exit { |player| player.in_pvp = false } -end - -# Defines the wilderness area action. -area_action :wilderness do - - on_entry do |player| - player.send(DisplayCrossbonesMessage.new(true)) - player.in_wilderness = true - end - - on_exit do |player| - player.send(DisplayCrossbonesMessage.new(false)) - player.in_wilderness = false - end - end \ No newline at end of file diff --git a/data/plugins/areas/areas.rb b/data/plugins/areas/areas.rb index cb540224..369dd2b7 100644 --- a/data/plugins/areas/areas.rb +++ b/data/plugins/areas/areas.rb @@ -1,11 +1,26 @@ require 'java' +java_import 'org.apollo.game.model.Position' +java_import 'org.apollo.game.model.entity.Entity$EntityType' java_import 'org.apollo.game.model.entity.Player' -# Todo make 0 the default height + + +# Creates a new area and registers it with the supplied coordinates. +def area(hash) + raise 'Hash must contain a name, coordinates, and actions pair.' unless hash.has_keys?(:name, :coordinates, :actions) + name = hash[:name]; coordinates = hash[:coordinates]; actions = hash[:actions] + + actions = [ actions ] if actions.is_a?(Symbol) + actions.map! { |action| AREA_ACTIONS[action]} + @areas << Area.new(name, coordinates, actions) +end + + +private # A map of coordinates (as an array) to areas. -AREAS = [] +@areas = [] # An area of the game world. class Area @@ -16,31 +31,70 @@ class Area @actions = actions end - # Called when the player has entered the area. - def entered(player) - actions.each { |action| action.entered(player) } + def min_x() # TODO better data structure and methods than this + @coordinates[0] end - # Called whilst the player is inside the area. + def min_y() + @coordinates[1] + end + + def max_x() + @coordinates[2] + end + + def max_y() + @coordinates[3] + end + + def height() + @coordinates[4] + end + + # Called when the player has entered the area. + def entered(player) + @actions.each { |action| action.entered(player) } + end + + # Called when the player has moved, but is still inside the area (and was in the area before). def inside(player) - acttions.each { |action| action.inside(player) } + @actions.each { |action| action.inside(player) } end # Called when the player has exited the area. def exited(player) - actions.each { |action| action.exited(player) } + @actions.each { |action| action.exited(player) } end end -# Creates a new area and registers it with the supplied coordinates. -def area(hash) - raise 'Hash must contain a name, coordinates, and actions pair.' unless hash.has_keys?(:name, :coordinates, :actions) - name = hash[:name]; coordinates = hash[:coordinates]; actions = hash[:actions] +# Listen for the MobPositionUpdateEvent and update the area listeners if appropriate. +on :mob_position_update do |event| + mob = event.mob + next unless mob.entity_type == EntityType::PLAYER - AREAS << Area.new(name, coordinates, actions.is_a?(Symbol) ? [actions] : actions) + old = mob.position + @areas.each do |area| + was_inside = old.inside(area) + next_inside = event.next.inside(area) + + if was_inside + if next_inside then area.inside(mob) else area.exited(mob) end + else + area.entered(mob) if next_inside + end + end end -# Coordinates refer to the bottom-left position (min_x, min_y) and the top-right position (max_x, max_y), followed by the height (optional). -area :name => :wilderness, :coordinates => [ 2944, 3520, 3392, 6400, 0 ], :actions => [ :pvp, :multicombat, :wilderness ] -area :name => :duel_arena, :coordinates => [ 3327, 3200, 3392, 3286 ], :actions => :pvp \ No newline at end of file +# The existing Position class. +class Position + + # Returns whether or not this Position is inside the specified Area. + def inside(area) + return false if (x < area.min_x() || x > area.max_x() || y < area.min_y() || y > area.max_y()) + z = area.height() + + return true if (z.nil? || z == height) + end + +end \ No newline at end of file