diff --git a/data/plugins/areas/actions.rb b/data/plugins/areas/actions.rb index 316c63e6..e72f42f4 100644 --- a/data/plugins/areas/actions.rb +++ b/data/plugins/areas/actions.rb @@ -49,7 +49,7 @@ end # Defines the pvp area action. area_action :pvp do on_entry { |player| player.in_pvp = true } - on_exit { |player| player.in_pvp = true } + on_exit { |player| player.in_pvp = false } end # Defines the wilderness area action. diff --git a/data/plugins/areas/areas.rb b/data/plugins/areas/areas.rb index 3dc06e8f..cb540224 100644 --- a/data/plugins/areas/areas.rb +++ b/data/plugins/areas/areas.rb @@ -42,5 +42,5 @@ def area(hash) 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, 3391, 3967, 0 ], :actions => [ :pvp, :multicombat, :wilderness ] +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 diff --git a/data/plugins/dialogue/dialogue.rb b/data/plugins/dialogue/dialogue.rb new file mode 100644 index 00000000..301cf771 --- /dev/null +++ b/data/plugins/dialogue/dialogue.rb @@ -0,0 +1,426 @@ +require 'java' + +java_import 'org.apollo.game.model.inter.dialogue.DialogueAdapter' +java_import 'org.apollo.game.message.impl.CloseInterfaceMessage' +java_import 'org.apollo.game.message.impl.SetWidgetItemModelMessage' +java_import 'org.apollo.game.message.impl.SetWidgetNpcModelMessage' +java_import 'org.apollo.game.message.impl.SetWidgetPlayerModelMessage' +java_import 'org.apollo.game.message.impl.SetWidgetTextMessage' + +# Defines a dialogue, with the specified name and block. +def dialogue(name, &block) + raise 'Dialogues must have a name and block.' if (name.nil? || block.nil?) + + dialogue = Dialogue.new(name) + dialogue.instance_eval(&block) + dialogue.wrap + DIALOGUES[name] = dialogue +end + +# Defines an opening (i.e. conversation starter) dialogue, which hooks into the chain. +# Allows for a lambda prerequisite to be passed, which takes one argument the player; if the prerequisite evaluates to false, the dialogue will not be opened. +def opening_dialogue(name, prerequisite=nil, &block) + dialogue = dialogue(name, &block) + npc = dialogue.npc + raise 'Npc cannot be null when opening a dialogue.' if npc.nil? + + on :message, :first_npc_action, npc do |ctx, player, event| + player.open_dialogue(name) if (prerequisite.nil? || prerequisite.call(player)) + end +end + +# Declares an emote, with the specified name and id. +def declare_emote(name, id) + EMOTES[name] = id +end + + + +private + +# The hash of dialogue names to dialogues. +DIALOGUES = {} + +# The hash of emote names to ids. +EMOTES = {} + +# The maximum amount of lines of text that can be displayed on a dialogue. +MAXIMUM_LINE_COUNT = 4 + +# The maximum amount of options that can be displayed on a dialogue. +MAXIMUM_OPTION_COUNT = 5 + +# The maximum width of a line, in characters. +MAXIMUM_LINE_WIDTH = 55 + +# The possible types of a dialogue. +DIALOGUE_TYPES = [ :message_with_item, :message_with_model, :npc_speech, :options, :player_speech, :text ] + +# A type of dialogue. +class Dialogue + attr_reader :emote, :name, :media, :options, :text, :title, :type + + # Initializes the Dialogue. + def initialize(name) + @name = name.to_s + @text = [] + @options = [] + end + + # Closes the dialogue interface when the player clicks the 'Click here to continue...' text. + def close + continue(:close => true) + end + + # Defines the event that occurs when a player clicks the 'Click here to continue...' text. + def continue(type=nil, &block) + raise 'Cannot add a continue event on a dialogue with options.' unless @options.size.zero? + raise 'Must declare either a type or a block for a continue event.' if (type.nil? && block.nil?) + + @options << (block.nil? ? get_next_dialogue(type) : block) + end + + # Sets the emote performed by the dialogue head. + def emote(emote=nil) + raise 'Can only perform an emote on :player_speech or :npc_speech dialogues.' unless [ :npc_speech, :player_speech ].include?(@type) + @emote = EMOTES[emote] if emote.kind_of?(Symbol) + @emote + end + + # Gets the media of this dialogue. + def media() + case @type + when :message_with_item then @item + when :npc_speech then @npc + when :message_with_model then @model + else raise "Cannot get media for #{@type}." + end + end + + # Sets the id of the item displayed. + def item(item=nil, scale=nil) + unless item.nil? + raise 'Can only display an item on :message_with_item dialogues.' unless @type == :message_with_item + @item = item + @item_scale = scale + end + + @item + end + + # Sets the id of the model displayed. + def model(model=nil) + unless model.nil? + raise 'Can only display a model on :message_with_model dialogues.' unless @type == :message_with_model + @model = model + end + + @model + end + + # Sets the id of the npc displayed. + def npc(npc=nil) + raise 'Can only display an npc on :npc_speech dialogues.' unless @type == :npc_speech + @npc = lookup_npc(npc) unless npc.nil? + @npc + end + + # Defines an option, displaying the specified message. + def option(message, type) + raise 'Can only display options on an :options dialogue.' unless @type == :options + raise "Cannot display more than #{MAXIMUM_OPTION_COUNT} options on a dialogue." unless @options.size < MAXIMUM_OPTION_COUNT + + @options[text.size] = get_next_dialogue(type) + @text << message + end + + # Gets the array of options. + def options + @options.dup + end + + # Appends a message to the text list. + def text(*message) + unless message.nil? + @text.concat(message) + end + + @text + end + + # Sets the title of the dialogue. + def title(title=nil) + @title = title unless title.nil? + @title + end + + # Sets the type of dialogue. + def type(type=nil) + unless type.nil? + verify_dialogue_type(type) + @type = type + end + + @type + end + + # Wraps text in this Dialogue, inserting extra Dialogues in the chain if necessary. + def wrap + lines = [] + next if @type == :options + + text = @text[0] + segments = []# text.chars.each_slice(MAXIMUM_LINE_WIDTH).map(&:join) # Split text into array of strings with length <= 60. + previous = 0; index = MAXIMUM_LINE_WIDTH + + while index < text.length + index -= 1 until text[index] == ' ' + segments << text[previous..index] + previous = index + index += MAXIMUM_LINE_WIDTH + end + segments << text[previous..text.length] + + if (segments.size <= MAXIMUM_LINE_COUNT) + lines.concat(segments) + @text = @text.drop(1) + insert_copy(@text) if @text.size > 0 + else + remaining = MAXIMUM_LINE_COUNT - segments.size + lines.concat(segments.first(remaining)) + insert_copy(segments.drop(remaining).join().concat(@text.drop(1))) + end + + @text = lines + end + + + # Copies the value of every variable from the specified Dialogue, optionally updating the text array. + def copy_from(dialogue, text=nil) + @emote = dialogue.emote + @item = dialogue.item + @model = dialogue.model + @npc = dialogue.npc + @options = dialogue.options + @text = if text.nil? then dialogue.text.dup else text.dup end + @type = dialogue.type + end + + private + + # Inserts a copy of this Dialogue into the chain, but with different text. + def insert_copy(text) + name = @name + index = name.index('-auto-inserted-') + + id = if index.nil? then 0 else name[name.rindex('-')..-1].to_i + 1 end + index ||= -1 + name = "#{name[0..index]}-auto-inserted-#{id}" + + dialogue = Dialogue.new(name) + dialogue.copy_from(self, text.dup) + dialogue.wrap() + + DIALOGUES[name] = dialogue + @options[0] = ->(player) { send_dialogue(player, dialogue) } + end + + # Decodes the next dialogue interface from the hash, returning a proc. + def get_next_dialogue(hash) + hash.keys.each do |key| + case key + when :close + return ->(player) { player.send(CloseInterfaceMessage.new) } + when :dialogue + return ->(player) { send_dialogue(player, lookup_dialogue(hash[key])) } + else raise "Unrecognised dialogue continue type #{key}." + end + end + end + +end + +# The existing Player class. +class Player + + # Opens the dialogue with the specified name. + def open_dialogue(name) + dialogue = lookup_dialogue(name) + send_dialogue(self, dialogue) + end + +end + + + +# Gets a Dialogue using the name it was registered with. +def lookup_dialogue(name) + dialogue = DIALOGUES[name] + raise "No dialogue named #{name.to_s}." if dialogue.nil? + + dialogue +end + +# Sends the specified dialogue. +def send_dialogue(player, dialogue) + type = dialogue.type + + case type + when :message_with_item then send_item_dialogue(player, dialogue) + when :message_with_model then send_model_dialogue(player, dialogue) + when :npc_speech then send_npc_dialogue(player, dialogue) + when :options then send_options_dialogue(player, dialogue) + when :player_speech then send_player_dialogue(player, dialogue) + when :text then send_text_dialogue(player, dialogue) + else raise "Unrecognised dialogue type #{type}." + end +end + +# The dialogue interface ids for dialogues that only display text, ordered by line count. +TEXT_DIALOGUE_IDS = [ 356, 359, 363, 368, 374 ] + +# The dialogue interface ids for dialogues that display the head of the player, ordered by line count. +PLAYER_DIALOGUE_IDS = [ 968, 973, 979, 986 ] + +# The dialogue interface ids for dialogues that display the head of an npc, ordered by line count. +NPC_DIALOGUE_IDS = [ 4882, 4887, 4893, 4900 ] + +# The dialogue interface ids for option dialogues, ordered by (option_count - 1) +OPTIONS_DIALOGUE_IDS = [ 2459, 2469, 2480, 2492 ] + +# Sends a dialogue displaying only text. +def send_text_dialogue(player, dialogue) + title = dialogue.title + send_generic_dialogue(player, dialogue, title, TEXT_DIALOGUE_IDS) +end + +# Sends a dialogue displaying the player's head. +def send_player_dialogue(player, dialogue) + send_generic_dialogue(player, dialogue, PLAYERS_DIALOGUE_IDS, ->(id) { SetWidgetPlayerModelMessage.new(id + 1) }) +end + +# Sends a dialogue displaying the head of an npc. +def send_npc_dialogue(player, dialogue) + npc = dialogue.npc + name = NpcDefinition.lookup(npc).name.to_s + name = "" if (name.nil? || name == "null") + + send_generic_dialogue(player, dialogue, name, NPC_DIALOGUE_IDS, ->(id) { SetWidgetNpcModelMessage.new(id + 1, npc)}) +end + + +# Sends a dialogue displaying an event. +def send_generic_dialogue(player, dialogue, title, ids, event=nil) + text = dialogue.text + dialogue_id = ids[text.size - 1] + player.send(event.call(dialogue_id)) unless event.nil? + + set_text(player, dialogue_title_id(dialogue_id), title) + + text.each_index { |index| set_text(player, dialogue_text_id(dialogue_id, index), text[index]) } + player.interface_set.open_dialogue(ContinueDialogueAdapter.new(player, dialogue.options[0]), dialogue_id) # TODO listener!!! +end + + +# Sends an options dialogue interface. +def send_options_dialogue(player, dialogue) + options = dialogue.options + size = options.size + raise 'Illegal options count: must be between 2 and 5, inclusive.' unless (2..5).include?(size) + + text = dialogue.text + dialogue_id = OPTIONS_DIALOGUE_IDS[size - 1] + + question = dialogue.title + set_text(player, dialogue_question_id(dialogue_id), question) + + text.each_index { |index| set_text(player, dialogue_option_id(dialogue_id, index), text[index]) } + player.interface_set.open_dialogue(OptionDialogueAdapter.new(player, options), dialogue_id) # TODO listener!!! +end + + +# A DialogueAdapter for dialogues with a 'Click here to continue...' message. +class ContinueDialogueAdapter < DialogueAdapter + + # Creates the ContinueDialogueAdadpter. + def initialize(player, continue) + super() + @player = player + @continue = continue + end + + # Executes the 'continue' lambda when the player clicks the 'Click here to continue...' message. + def continued() + @continue.call(@player) + end + +end + + +# A DialogueAdapter for dialogues with a set of options that can be selected. +class OptionDialogueAdapter < DialogueAdapter + + # Creates the OptionDialogueAdadpter. + def initialize(player, options) + super() + @player = player + @options = options.dup + end + + # Executes an option. + def button_clicked(button) + option = OPTIONS_DIALOGUE_IDS.find_index(button) + options[option].call(@player) + end + +end + + +# Gets the widget id of the question, for an options dialogue interface. +def dialogue_question_id(id) + id + 1 +end + +# Gets the widget id of a dialogue option. +def dialogue_option_id(id, option) + id + 1 + option +end + +# Gets the widget id of a dialogue text line. +def dialogue_text_id(id, line) + id + 3 + line +end + +# Gets the widget id of a dialogue title. +def dialogue_title_id(id) + id + 2 +end + +# Sets the text of a widget. +def set_text(player, id, message) + player.send(SetWidgetTextMessage.new(id, message)) +end + +# Verifies that the dialogue type exists. +def verify_dialogue_type(type) + raise "Unrecognised dialogue type #{type}, expected one of #{DIALOGUE_TYPES}." unless DIALOGUE_TYPES.include?(type) +end + +# The spacing of each character glyph, for the font used for dialogue. TODO decode the font from the cache. +GLYPH_SPACING = [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 7, 14, 9, 12, 12, 4, 5, + 5, 10, 8, 4, 8, 4, 7, 9, 7, 9, 8, 8, 8, 9, 7, 9, 9, 4, 5, 7, + 9, 7, 9, 14, 9, 8, 8, 8, 7, 7, 9, 8, 6, 8, 8, 7, 10, 9, 9, 8, + 9, 8, 8, 6, 9, 8, 10, 8, 8, 8, 6, 7, 6, 9, 10, 5, 8, 8, 7, 8, + 8, 7, 8, 8, 4, 7, 7, 4, 10, 8, 8, 8, 8, 6, 8, 6, 8, 8, 9, 8, + 8, 8, 6, 4, 6, 12, 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 8, 11, 8, 8, 4, 8, 7, 12, 6, 7, 9, 5, 12, 5, 6, 10, 6, 6, 6, + 8, 8, 4, 5, 5, 6, 7, 11, 11, 11, 9, 9, 9, 9, 9, 9, 9, 13, 8, 8, + 8, 8, 8, 4, 4, 5, 4, 8, 9, 9, 9, 9, 9, 9, 8, 10, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 13, 6, 8, 8, 8, 8, 4, 4, 5, 4, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ] + +def get_width(char) + +end \ No newline at end of file diff --git a/data/plugins/dialogue/plugin.xml b/data/plugins/dialogue/plugin.xml new file mode 100644 index 00000000..667266b9 --- /dev/null +++ b/data/plugins/dialogue/plugin.xml @@ -0,0 +1,16 @@ + + + dialogue + 0.1 + Dialogue + Adds dialogue support. + + Major + + + + + + util + + \ No newline at end of file diff --git a/data/plugins/util/name-lookup.rb b/data/plugins/util/name-lookup.rb index f45b5788..febb8be8 100644 --- a/data/plugins/util/name-lookup.rb +++ b/data/plugins/util/name-lookup.rb @@ -24,7 +24,7 @@ def lookup_entity(type, name) return cached unless cached.nil? id = name[name.rindex(' ') + 1, name.length - 1].to_i if name.include?(' ') - id = find_entities(type, name, 1).first if (id .nil? || id.zero?) + id = find_entities(type, name, 1).first if (id.nil? || id.zero?) raise "The #{type} called #{name} could not be identified." if id.nil? diff --git a/src/org/apollo/Server.java b/src/org/apollo/Server.java index 2534bd29..dc97737c 100644 --- a/src/org/apollo/Server.java +++ b/src/org/apollo/Server.java @@ -167,7 +167,7 @@ public final class Server { serviceManager.startAll(); int releaseNo = context.getRelease().getReleaseNumber(); - IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs/", Integer.toString(releaseNo)), true); + IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs", Integer.toString(releaseNo)), true); World.getWorld().init(releaseNo, fs, manager); } diff --git a/src/org/apollo/fs/IndexedFileSystem.java b/src/org/apollo/fs/IndexedFileSystem.java index 40b3bef1..50d3ee0c 100644 --- a/src/org/apollo/fs/IndexedFileSystem.java +++ b/src/org/apollo/fs/IndexedFileSystem.java @@ -177,7 +177,7 @@ public final class IndexedFileSystem implements Closeable { int nextType = header[7] & 0xFF; if (i != curChunk) { - throw new IOException("Chunk id mismatch."); + Preconditions.checkArgument(i == curChunk, "Chunk id mismatch."); } int chunkSize = size - read; diff --git a/src/org/apollo/game/message/impl/FifthNpcActionMessage.java b/src/org/apollo/game/message/impl/FifthNpcActionMessage.java index 9f5331b0..02347bcb 100644 --- a/src/org/apollo/game/message/impl/FifthNpcActionMessage.java +++ b/src/org/apollo/game/message/impl/FifthNpcActionMessage.java @@ -1,16 +1,17 @@ package org.apollo.game.message.impl; /** - * The third {@link NpcActionMessage}. - * + * The fifth {@link NpcActionMessage}. + * + * @author Major * @author Stuart */ public final class FifthNpcActionMessage extends NpcActionMessage { /** - * Creates a new third npc action message. + * Creates the FifthNpcActionMessage. * - * @param index The index of the npc. + * @param index The index of the Npc. */ public FifthNpcActionMessage(int index) { super(5, index); diff --git a/src/org/apollo/game/message/impl/FourthNpcActionMessage.java b/src/org/apollo/game/message/impl/FourthNpcActionMessage.java index 952f06f7..d0babf44 100644 --- a/src/org/apollo/game/message/impl/FourthNpcActionMessage.java +++ b/src/org/apollo/game/message/impl/FourthNpcActionMessage.java @@ -1,16 +1,17 @@ package org.apollo.game.message.impl; /** - * The third {@link NpcActionMessage}. - * + * The fourth {@link NpcActionMessage}. + * + * @author Major * @author Stuart */ public final class FourthNpcActionMessage extends NpcActionMessage { /** - * Creates a new third npc action message. - * - * @param index The index of the npc. + * Creates the FourthNpcActionMessage. + * + * @param index The index of the Npc. */ public FourthNpcActionMessage(int index) { super(4, index); diff --git a/src/org/apollo/game/message/impl/HintIconMessage.java b/src/org/apollo/game/message/impl/HintIconMessage.java new file mode 100644 index 00000000..dff7f252 --- /dev/null +++ b/src/org/apollo/game/message/impl/HintIconMessage.java @@ -0,0 +1,102 @@ +package org.apollo.game.message.impl; + +import java.util.Optional; + +import org.apollo.game.message.Message; +import org.apollo.game.model.Position; + +/** + * A {@link Message} that displays a hint icon over an Npc, tile, or player. + * + * @author Major + */ +public final class HintIconMessage extends Message { + + // TODO identify the other types and use an enum. + + /** + * The hint icon type for Npcs. + */ + public static final int NPC_TYPE = 1; + + /** + * The hint icon type for Players. + */ + public static final int PLAYER_TYPE = 10; + + /** + * Creates a HintIconMessage for the Npc with the specified index. + * + * @param index The index of the Npc. + * @return The HintIconMessage. + */ + public static HintIconMessage forNpc(int index) { + return new HintIconMessage(NPC_TYPE, Optional.of(index), Optional.empty()); + } + + /** + * Creates a HintIconMessage for the Player with the specified index. + * + * @param index The index of the Player. + * @return The HintIconMessage. + */ + public static HintIconMessage forPlayer(int index) { + return new HintIconMessage(PLAYER_TYPE, Optional.of(index), Optional.empty()); + } + + /** + * The index of the entity, if applicable. + */ + private final Optional index; + + /** + * The Position of the tile, if applicable. + */ + private final Optional position; + + /** + * The type of entity this HintIconMessage is directed at. + */ + private final int type; + + /** + * Creates the HintIconMessage. + * + * @param type The type of entity this HintIconMessage is directed at. + * @param index The index of the entity, if applicable. + * @param position The Position of the tile, if applicable. + */ + private HintIconMessage(int type, Optional index, Optional position) { + this.type = type; + this.index = index; + this.position = position; + } + + /** + * Gets the index of the entity, if applicable. + * + * @return The index. + */ + public Optional getIndex() { + return index; + } + + /** + * Gets the {@link Position} of the tile, if applicable. + * + * @return The Position. + */ + public Optional getPosition() { + return position; + } + + /** + * Gets the type this HintIconMessage is directed at. + * + * @return The type. + */ + public int getType() { + return type; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/MagicOnMobMessage.java b/src/org/apollo/game/message/impl/MagicOnMobMessage.java index eb30e23c..939e8086 100644 --- a/src/org/apollo/game/message/impl/MagicOnMobMessage.java +++ b/src/org/apollo/game/message/impl/MagicOnMobMessage.java @@ -4,63 +4,65 @@ import org.apollo.game.message.Message; import org.apollo.game.model.entity.Entity; /** - * A {@link Message} sent by the client representing when a player uses any type of magic spell on a mob. + * A {@link Message} sent by the client when a Player uses a magic spell on a Mob. * * @author Stuart */ public abstract class MagicOnMobMessage extends Message { - /** - * The type of the mob - */ - private final Entity.EntityType type; - /** - * The index of the mob - */ - private final int index; - /** - * The spell if used - */ - private final int spellId; + /** + * The type of the Mob. + */ + private final Entity.EntityType type; - /** - * Creates a magic on mob message - * - * @param type The mob type - * @param index The mob index - * @param spellId The spell id - */ - public MagicOnMobMessage(Entity.EntityType type, int index, int spellId) { - this.type = type; - this.index = index; - this.spellId = spellId; - } + /** + * The index of the Mob. + */ + private final int index; - /** - * Gets the type of the mob the spell is being used on - * - * @return The mob type - */ - public Entity.EntityType getType() { - return type; - } + /** + * The spell if used. + */ + private final int spellId; - /** - * Gets the index of the mob the spell is being used on - * - * @return The mob index - */ - public int getIndex() { - return index; - } + /** + * Creates the MagicOnMobMessage. + * + * @param type The Mob type. + * @param index The Mob index. + * @param spellId The spell id. + */ + public MagicOnMobMessage(Entity.EntityType type, int index, int spellId) { + this.type = type; + this.index = index; + this.spellId = spellId; + } - /** - * Gets the spell id that is being used - * - * @return The spell id - */ - public int getSpellId() { - return spellId; - } + /** + * Gets the type of the Mob the spell is being used on. + * + * @return The Mob type. + */ + public Entity.EntityType getType() { + return type; + } + + /** + * Gets the index of the Mob the spell is being used on. + * + * @return The Mob index. + */ + public int getIndex() { + return index; + } + + /** + * Gets the spell id that is being used. + * + * @return The spell id. + */ + public int getSpellId() { + return spellId; + } } \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/MagicOnNpcMessage.java b/src/org/apollo/game/message/impl/MagicOnNpcMessage.java index f6acb656..52e562b2 100644 --- a/src/org/apollo/game/message/impl/MagicOnNpcMessage.java +++ b/src/org/apollo/game/message/impl/MagicOnNpcMessage.java @@ -1,23 +1,22 @@ package org.apollo.game.message.impl; import org.apollo.game.model.entity.Entity; -import org.apollo.game.model.entity.Npc; /** - * The magic on npc {@link org.apollo.game.message.impl.MagicOnNpcMessage} + * The magic on npc {@link MagicOnNpcMessage} * * @author Stuart */ public final class MagicOnNpcMessage extends MagicOnMobMessage { - /** - * Creates the magic on npc message - * - * @param index The npc index - * @param spellId The spell id used - */ - public MagicOnNpcMessage(int index, int spellId) { - super(Entity.EntityType.NPC, index, spellId); - } + /** + * Creates the MagicOnMobMessage. + * + * @param index The Npc index. + * @param spellId The spell id used. + */ + public MagicOnNpcMessage(int index, int spellId) { + super(Entity.EntityType.NPC, index, spellId); + } } diff --git a/src/org/apollo/game/message/impl/MagicOnPlayerMessage.java b/src/org/apollo/game/message/impl/MagicOnPlayerMessage.java index d0517f1f..5addfba7 100644 --- a/src/org/apollo/game/message/impl/MagicOnPlayerMessage.java +++ b/src/org/apollo/game/message/impl/MagicOnPlayerMessage.java @@ -3,20 +3,20 @@ package org.apollo.game.message.impl; import org.apollo.game.model.entity.Entity; /** - * The magic on player {@link org.apollo.game.message.impl.MagicOnMobMessage + * The Player {@link MagicOnMobMessage}. * * @author Stuart */ public final class MagicOnPlayerMessage extends MagicOnMobMessage { - /** - * Creates the magic on player message - * - * @param index The player index - * @param spellId The spell id used - */ - public MagicOnPlayerMessage(int index, int spellId) { - super(Entity.EntityType.PLAYER, index, spellId); - } + /** + * Creates the MagicOnPlayerMessage. + * + * @param index The index of the player. + * @param spellId The spell id used. + */ + public MagicOnPlayerMessage(int index, int spellId) { + super(Entity.EntityType.PLAYER, index, spellId); + } } \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/MouseClickedMessage.java b/src/org/apollo/game/message/impl/MouseClickedMessage.java index d7eab5d7..706d4cb2 100644 --- a/src/org/apollo/game/message/impl/MouseClickedMessage.java +++ b/src/org/apollo/game/message/impl/MouseClickedMessage.java @@ -4,79 +4,82 @@ import org.apollo.game.message.Message; /** * A {@link Message} sent by the client to indicate when the mouse button/s have been clicked. This can be used in - * combination with {@link org.apollo.game.message.impl.FocusUpdateMessage} to work out if the player is clicking - * whilst the client is closed + * combination with {@link FocusUpdateMessage} to work out if the player is clicking whilst the client is closed. * * @author Stuart + * @author Major */ public final class MouseClickedMessage extends Message { - /** - * Time in milliseconds since the last click - */ - private final long lastClickedDelay; - /** - * Right mouse button flag - */ - private final boolean rightMouseButton; - /** - * The y position of the cursor - */ - private final int x; - /** - * The x position of the cursor - */ - private final int y; + /** + * The time, in milliseconds, since the last click. + */ + private final long clickDelay; - /** - * Creates a new mouse clicked message - * - * @param lastClickedDelay The delay since the last click - * @param rightMouseButton Whether or not the right mouse button was used - * @param x The x cursor position when clicked - * @param y The y cursor position when clicked - */ - public MouseClickedMessage(long lastClickedDelay, boolean rightMouseButton, int x, int y) { - this.lastClickedDelay = lastClickedDelay; - this.rightMouseButton = rightMouseButton; - this.x = x; - this.y = y; - } + /** + * Indicates whether or not the mouse button pressed was the right mouse button. + */ + private final boolean right; - /** - * Gets the time in milliseconds since the last click - * - * @return The time in milliseconds since the last click - */ - public long getLastClickedDelay() { - return lastClickedDelay; - } + /** + * The y position of the cursor. + */ + private final int x; - /** - * Gets whether the right mouse button was used or not - * - * @return If the mouse right button was used to click - */ - public boolean usingRightMouseButton() { - return rightMouseButton; - } + /** + * The x position of the cursor. + */ + private final int y; - /** - * Gets the x position of the cursor - * - * @return The x position of the cursor when clicked - */ - public int getX() { - return x; - } + /** + * Creates the MouseClickedMessage. + * + * @param clickDelay The delay, in milliseconds, since the last click. + * @param right Whether or not the mouse button pressed was the right mouse button. + * @param x The x cursor position when clicked. + * @param y The y cursor position when clicked. + */ + public MouseClickedMessage(long clickDelay, boolean right, int x, int y) { + this.clickDelay = clickDelay; + this.right = right; + this.x = x; + this.y = y; + } - /** - * Gets the y position of the cursor - * - * @return The y position of the cursor when clicked - */ - public int getY() { - return y; - } + /** + * Gets the delay, in milliseconds, since the last click. + * + * @return The time delay. + */ + public long getClickDelay() { + return clickDelay; + } + + /** + * Gets the x position of the cursor. + * + * @return The x position of the cursor when clicked. + */ + public int getX() { + return x; + } + + /** + * Gets the y position of the cursor. + * + * @return The y position of the cursor when clicked. + */ + public int getY() { + return y; + } + + /** + * Returns whether or not the right mouse button was used. + * + * @return {@code true} if the right mouse button was used to click, {@code false} if not. + */ + public boolean wasRightMouseButton() { + return right; + } } diff --git a/src/org/apollo/game/model/area/Sector.java b/src/org/apollo/game/model/area/Sector.java index a8c140fc..e1c35d46 100644 --- a/src/org/apollo/game/model/area/Sector.java +++ b/src/org/apollo/game/model/area/Sector.java @@ -13,7 +13,6 @@ import org.apollo.game.model.entity.Entity; import org.apollo.game.model.entity.Entity.EntityType; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; /** @@ -23,16 +22,16 @@ import com.google.common.collect.ImmutableSet; */ public final class Sector { - /** - * The default size of newly-created sets, to reduce memory usage. - */ - private static final int DEFAULT_SET_SIZE = 2; - /** * The width and length of a sector, in tiles. */ public static final int SECTOR_SIZE = 8; + /** + * The default size of newly-created sets, to reduce memory usage. + */ + private static final int DEFAULT_SET_SIZE = 2; + /** * The sector coordinates of this sector. */ @@ -72,6 +71,7 @@ public final class Sector { * register it to this sector. * * @param entity The entity. + * @throws IllegalArgumentException If the entity does not belong in this sector. */ public void addEntity(Entity entity) { Position position = entity.getPosition(); @@ -82,17 +82,6 @@ public final class Sector { notifyListeners(entity, SectorOperation.ADD); } - /** - * Checks that the specified {@link Position} is included in this sector. - * - * @param position The position. - * @throws IllegalArgumentException If the specified position is not included in this sector. - */ - private void checkPosition(Position position) { - Preconditions.checkArgument(coordinates.equals(SectorCoordinates.fromPosition(position)), - "Position is not included in this sector."); - } - /** * Checks if this sector contains the specified entity. *

@@ -118,24 +107,24 @@ public final class Sector { } /** - * Gets a shallow copy of the {@link List} of {@link Entity} objects at the specified {@link Position}. The returned - * type will be {@link ImmutableList}. + * Gets a shallow copy of the {@link Set} of {@link Entity} objects at the specified {@link Position}. The returned + * type will be immutable. * * @param position The position containing the entities. * @return The list. */ - public List getEntities(Position position) { - return ImmutableList.copyOf(entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE))); + public Set getEntities(Position position) { + return ImmutableSet.copyOf(entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE))); } /** - * Gets a shallow copy of the {@link List} of {@link Entity}s with the specified {@link EntityType}. The returned - * list will be an {@link ImmutableList}. Type will be inferred from the call, so ensure that the entity type and - * the reference correspond, or this method will fail at runtime. + * Gets a shallow copy of the {@link Set} of {@link Entity}s with the specified {@link EntityType}. The returned + * type will be immutable. Type will be inferred from the call, so ensure that the entity type and the reference + * correspond, or this method will fail at runtime. * * @param position The {@link Position} containing the entities. * @param type The {@link EntityType}. - * @return The list of entities. + * @return The set of entities. */ public Set getEntities(Position position, EntityType type) { Set local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE)); @@ -145,6 +134,34 @@ public final class Sector { return ImmutableSet.copyOf(filtered); } + /** + * Moves the {@link Entity} that was in the specified {@code old} {@link Position}, to the current position of the + * entity. + *

+ * Both the {@code old} and current positions of the entity must belong to this sector. + * + * @param old The old position of the entity. + * @param entity The entity to move. + * @throws IllegalArgumentException If either of the positions do not belong to this sector. + */ + public void moveEntity(Position old, Entity entity) { + Position position = entity.getPosition(); + checkPosition(old); + checkPosition(position); + + Set local = entities.get(old); + + if (local == null || !local.remove(entity)) { + throw new IllegalArgumentException("Entity belongs in this sector but does not exist."); + } + + local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE)); + + local.add(entity); + notifyListeners(entity, SectorOperation.MOVE); + + } + /** * Notifies the {@link SectorListener}s registered to this sector that an update has occurred. * @@ -174,4 +191,15 @@ public final class Sector { notifyListeners(entity, SectorOperation.REMOVE); } + /** + * Checks that the specified {@link Position} is included in this sector. + * + * @param position The position. + * @throws IllegalArgumentException If the specified position is not included in this sector. + */ + private void checkPosition(Position position) { + Preconditions.checkArgument(coordinates.equals(SectorCoordinates.fromPosition(position)), + "Position is not included in this sector."); + } + } \ No newline at end of file diff --git a/src/org/apollo/game/model/area/SectorOperation.java b/src/org/apollo/game/model/area/SectorOperation.java index 14997350..a0df172d 100644 --- a/src/org/apollo/game/model/area/SectorOperation.java +++ b/src/org/apollo/game/model/area/SectorOperation.java @@ -12,6 +12,11 @@ public enum SectorOperation { */ ADD, + /** + * The move operation, when an entity has moved positions, but is still in the same sector. + */ + MOVE, + /** * The remove operation, when an entity has been removed from a sector. */ diff --git a/src/org/apollo/game/model/entity/Mob.java b/src/org/apollo/game/model/entity/Mob.java index ad4c6512..9240dc8e 100644 --- a/src/org/apollo/game/model/entity/Mob.java +++ b/src/org/apollo/game/model/entity/Mob.java @@ -419,15 +419,20 @@ public abstract class Mob extends Entity { * @param position The position. */ public final void setPosition(Position position) { + Position old = this.position; SectorRepository repository = World.getWorld().getSectorRepository(); - Sector current = repository.fromPosition(this.position); + Sector current = repository.fromPosition(old); - Sector next = position.inside(current) ? current : repository.fromPosition(position); + if (position.inside(current)) { + this.position = position; + current.moveEntity(old, this); + } else { + Sector next = repository.fromPosition(position); + current.removeEntity(this); + this.position = position; // addEntity relies on the position being updated, so do that first. - current.removeEntity(this); - this.position = position; // addEntity relies on the position being updated, so do that first. - - next.addEntity(this); + next.addEntity(this); + } } /** diff --git a/src/org/apollo/game/model/entity/Npc.java b/src/org/apollo/game/model/entity/Npc.java index 478b77a1..66532a96 100644 --- a/src/org/apollo/game/model/entity/Npc.java +++ b/src/org/apollo/game/model/entity/Npc.java @@ -13,19 +13,19 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; /** - * An {@link Npc} is a {@link Mob} that is not being controlled by a player. + * A {@link Mob} that is not controlled by a player. * * @author Major */ public final class Npc extends Mob { /** - * The positions representing the bounds (i.e. walking limits) of this npc. + * The positions representing the bounds (i.e. walking limits) of this Npc. */ private Position[] boundary; /** - * Creates a new npc with the specified id and {@link Position}. + * Creates a new Npc with the specified id and {@link Position}. * * @param id The id. * @param position The position. @@ -35,7 +35,7 @@ public final class Npc extends Mob { } /** - * Creates a new npc with the specified {@link NpcDefinition} and {@link Position}. + * Creates a new Npc with the specified {@link NpcDefinition} and {@link Position}. * * @param position The position. * @param definition The definition. @@ -57,7 +57,7 @@ public final class Npc extends Mob { } /** - * Gets the boundary of this npc. + * Gets the boundary of this Npc. * * @return The boundary. */ @@ -71,7 +71,7 @@ public final class Npc extends Mob { } /** - * Gets the id of this npc. + * Gets the id of this Npc. * * @return The id. */ @@ -87,16 +87,16 @@ public final class Npc extends Mob { } /** - * Indicates whether or not this npc is bound to a specific set of coordinates. + * Indicates whether or not this Npc is bound to a specific set of coordinates. * - * @return {@code true} if the npc is bound, otherwise {@code false}. + * @return {@code true} if the Npc is bound, otherwise {@code false}. */ public boolean isBound() { return boundary == null; } /** - * Sets the boundary of this npc. + * Sets the boundary of this Npc. * * @param boundary The boundary. */ @@ -111,7 +111,7 @@ public final class Npc extends Mob { } /** - * Transforms this npc into the npc with the specified id. + * Transforms this Npc into the Npc with the specified id. * * @param id The id. */ @@ -123,10 +123,10 @@ public final class Npc extends Mob { } /** - * Initialises this npc. + * Initialises this Npc. */ private void init() { - // This has to be here instead of in Mob#init because of ordering issues - the player cannot be added to the + // This has to be here instead of in Mob#init because of ordering issues - the Npc cannot be added to the // sector until their credentials have been set, which is only done after the super constructors are called. Sector sector = World.getWorld().getSectorRepository().get(position.getSectorCoordinates()); sector.addEntity(this); diff --git a/src/org/apollo/game/model/inter/InterfaceSet.java b/src/org/apollo/game/model/inter/InterfaceSet.java index 63fd4ea2..72835dac 100644 --- a/src/org/apollo/game/model/inter/InterfaceSet.java +++ b/src/org/apollo/game/model/inter/InterfaceSet.java @@ -2,6 +2,7 @@ package org.apollo.game.model.inter; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.apollo.game.message.impl.CloseInterfaceMessage; import org.apollo.game.message.impl.EnterAmountMessage; @@ -34,12 +35,12 @@ public final class InterfaceSet { /** * The current enter amount listener. */ - private EnterAmountListener amountListener; + private Optional amountListener = Optional.empty(); /** * The current chat box dialogue listener. */ - private DialogueListener dialogueListener; + private Optional dialogueListener = Optional.empty(); /** * A map of open interfaces. @@ -49,12 +50,12 @@ public final class InterfaceSet { /** * The current listener. */ - private InterfaceListener listener; + private Optional listener = Optional.empty(); /** * The player whose interfaces are being managed. */ - private final Player player; // TODO: maybe switch to a listener system like the inventory? + private final Player player; /** * Creates an interface set. @@ -72,8 +73,8 @@ public final class InterfaceSet { * @return {@code true} if the message handler chain should be broken. */ public boolean buttonClicked(int button) { - if (dialogueListener != null) { - return dialogueListener.buttonClicked(button); + if (dialogueListener.isPresent()) { + return dialogueListener.get().buttonClicked(button); } return false; } @@ -86,21 +87,6 @@ public final class InterfaceSet { player.send(new CloseInterfaceMessage()); } - /** - * An internal method for closing the interface, notifying the listener if appropriate, but not sending any - * messages. - */ - private void closeAndNotify() { - amountListener = null; - dialogueListener = null; - - interfaces.clear(); - if (listener != null) { - listener.interfaceClosed(); - listener = null; - } - } - /** * Checks if this interface sets contains the specified interface. * @@ -125,8 +111,8 @@ public final class InterfaceSet { * Called when the player has clicked the "Click here to continue" button on a dialogue. */ public void continueRequested() { - if (dialogueListener != null) { - dialogueListener.continued(); + if (dialogueListener.isPresent()) { + dialogueListener.get().continued(); } } @@ -136,9 +122,9 @@ public final class InterfaceSet { * @param amount The amount. */ public void enteredAmount(int amount) { - if (amountListener != null) { - amountListener.amountEntered(amount); - amountListener = null; + if (amountListener.isPresent()) { + amountListener.get().amountEntered(amount); + amountListener = Optional.empty(); } } @@ -158,8 +144,8 @@ public final class InterfaceSet { public void openDialogue(DialogueListener listener, int dialogueId) { closeAndNotify(); - this.dialogueListener = listener; - this.listener = listener; + this.dialogueListener = Optional.ofNullable(listener); + this.listener = Optional.ofNullable(listener); interfaces.put(InterfaceType.DIALOGUE, dialogueId); player.send(new OpenDialogueInterfaceMessage(dialogueId)); @@ -180,7 +166,7 @@ public final class InterfaceSet { * @param listener The enter amount listener. */ public void openEnterAmountDialogue(EnterAmountListener listener) { - amountListener = listener; + amountListener = Optional.of(listener); player.send(new EnterAmountMessage()); } @@ -201,7 +187,7 @@ public final class InterfaceSet { */ public void openWindow(InterfaceListener listener, int windowId) { closeAndNotify(); - this.listener = listener; + this.listener = Optional.ofNullable(listener); interfaces.put(InterfaceType.WINDOW, windowId); player.send(new OpenInterfaceMessage(windowId)); @@ -226,7 +212,7 @@ public final class InterfaceSet { */ public void openWindowWithSidebar(InterfaceListener listener, int windowId, int sidebarId) { closeAndNotify(); - this.listener = listener; + this.listener = Optional.ofNullable(listener); interfaces.put(InterfaceType.WINDOW, windowId); interfaces.put(InterfaceType.SIDEBAR, sidebarId); @@ -243,4 +229,19 @@ public final class InterfaceSet { return interfaces.size(); } + /** + * An internal method for closing the interface, notifying the listener if appropriate, but not sending any + * messages. + */ + private void closeAndNotify() { + amountListener = Optional.empty(); + dialogueListener = Optional.empty(); + + interfaces.clear(); + if (listener.isPresent()) { + listener.get().interfaceClosed(); + listener = Optional.empty(); + } + } + } \ No newline at end of file diff --git a/src/org/apollo/game/model/inv/Inventory.java b/src/org/apollo/game/model/inv/Inventory.java index b94a8ed5..5e9fd664 100644 --- a/src/org/apollo/game/model/inv/Inventory.java +++ b/src/org/apollo/game/model/inv/Inventory.java @@ -122,19 +122,17 @@ public final class Inventory { } /** - * Attempts to add as much of the specified {@code item} to this inventory - * as possible. If any of the item remains, an {@link Item item with the - * remainder} will be returned (in the case of stack-able items, any - * quantity that remains in the stack is returned). If nothing remains, the - * method will return {@link Optional#empty an empty Optional}. + * Attempts to add as much of the specified {@code item} to this inventory as possible. If any of the item remains, + * an {@link Item item with the remainder} will be returned (in the case of stack-able items, any quantity that + * remains in the stack is returned). If nothing remains, the method will return {@link Optional#empty an empty + * Optional}. * *

- * If anything remains at all, the listener will be notified which could be - * used for notifying a player that their inventory is full, for example. + * If anything remains at all, the listener will be notified which could be used for notifying a player that their + * inventory is full, for example. * * @param item The item to add to this inventory. - * @return The item that may remain, if nothing remains, - * {@link Optional#empty an empty Optional} is returned. + * @return The item that may remain, if nothing remains, {@link Optional#empty an empty Optional} is returned. */ public Optional add(Item item) { int id = item.getId(); @@ -463,10 +461,10 @@ public final class Inventory { if (amount >= item.getAmount()) { set(slot, null); return item.getAmount(); - } else { - set(slot, new Item(item.getId(), item.getAmount() - amount)); - return amount; } + + set(slot, new Item(item.getId(), item.getAmount() - amount)); + return amount; } return 0; diff --git a/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java b/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java index 17dae8b4..e3155924 100644 --- a/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java +++ b/src/org/apollo/game/sync/task/PlayerSynchronizationTask.java @@ -69,13 +69,13 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { List segments = new ArrayList<>(); for (Iterator it = localPlayers.iterator(); it.hasNext();) { - Player p = it.next(); - if (!p.isActive() || p.isTeleporting() - || p.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance()) { + Player other = it.next(); + if (!other.isActive() || other.isTeleporting() + || other.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance()) { it.remove(); segments.add(new RemoveMobSegment()); } else { - segments.add(new MovementSegment(p.getBlockSet(), p.getDirections())); + segments.add(new MovementSegment(other.getBlockSet(), other.getDirections())); } } @@ -83,7 +83,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { MobRepository repository = World.getWorld().getPlayerRepository(); for (Iterator it = repository.iterator(); it.hasNext();) { - Player p = it.next(); + Player other = it.next(); if (localPlayers.size() >= 255) { player.flagExcessivePlayers(); break; @@ -91,19 +91,19 @@ public final class PlayerSynchronizationTask extends SynchronizationTask { break; } - if (p != player && p.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance()) - && !localPlayers.contains(p)) { - localPlayers.add(p); + if (other != player && other.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance()) + && !localPlayers.contains(other)) { + localPlayers.add(other); added++; - blockSet = p.getBlockSet(); + blockSet = other.getBlockSet(); if (!blockSet.contains(AppearanceBlock.class)) { // TODO check if client has cached appearance blockSet = blockSet.clone(); - blockSet.add(SynchronizationBlock.createAppearanceBlock(p)); + blockSet.add(SynchronizationBlock.createAppearanceBlock(other)); } - segments.add(new AddPlayerSegment(blockSet, p.getIndex(), p.getPosition())); + segments.add(new AddPlayerSegment(blockSet, other.getIndex(), other.getPosition())); } } diff --git a/src/org/apollo/net/release/r317/FifthNpcActionMessageDecoder.java b/src/org/apollo/net/release/r317/FifthNpcActionMessageDecoder.java index 7490bd39..01096bbe 100644 --- a/src/org/apollo/net/release/r317/FifthNpcActionMessageDecoder.java +++ b/src/org/apollo/net/release/r317/FifthNpcActionMessageDecoder.java @@ -8,16 +8,17 @@ import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.FifthNpcActionMessage}. + * A {@link MessageDecoder} for the {@link FifthNpcActionMessage}. * * @author Stuart + * @author Major */ public final class FifthNpcActionMessageDecoder extends MessageDecoder { @Override public FifthNpcActionMessage decode(GamePacket packet) { GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE); + int index = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE); return new FifthNpcActionMessage(index); } diff --git a/src/org/apollo/net/release/r317/FourthNpcActionMessageDecoder.java b/src/org/apollo/net/release/r317/FourthNpcActionMessageDecoder.java index a77bea34..f208cdac 100644 --- a/src/org/apollo/net/release/r317/FourthNpcActionMessageDecoder.java +++ b/src/org/apollo/net/release/r317/FourthNpcActionMessageDecoder.java @@ -7,16 +7,17 @@ import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.FourthNpcActionMessage}. + * A {@link MessageDecoder} for the {@link FourthNpcActionMessage}. * * @author Stuart + * @author Major */ public final class FourthNpcActionMessageDecoder extends MessageDecoder { @Override public FourthNpcActionMessage decode(GamePacket packet) { GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT); + int index = (int) reader.getUnsigned(DataType.SHORT); return new FourthNpcActionMessage(index); } diff --git a/src/org/apollo/net/release/r317/HintIconMessageEncoder.java b/src/org/apollo/net/release/r317/HintIconMessageEncoder.java new file mode 100644 index 00000000..b8be56c3 --- /dev/null +++ b/src/org/apollo/net/release/r317/HintIconMessageEncoder.java @@ -0,0 +1,34 @@ +package org.apollo.net.release.r317; + +import org.apollo.game.message.impl.HintIconMessage; +import org.apollo.net.codec.game.DataType; +import org.apollo.net.codec.game.GamePacket; +import org.apollo.net.codec.game.GamePacketBuilder; +import org.apollo.net.release.MessageEncoder; + +/** + * A {@link MessageEncoder} for the {@link HintIconMessage}. + * + * @author Major + */ +public final class HintIconMessageEncoder extends MessageEncoder { + + @Override + public GamePacket encode(HintIconMessage message) { + GamePacketBuilder builder = new GamePacketBuilder(254); + int type = message.getType(); + builder.put(DataType.BYTE, type); + + switch (type) { + case HintIconMessage.NPC_TYPE: + case HintIconMessage.PLAYER_TYPE: + builder.put(DataType.SHORT, message.getIndex().get()); + break; + default: + throw new IllegalStateException("Unsupported hint icon type " + type + "."); + } + + return builder.toGamePacket(); + } + +} \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/MagicOnNpcMessageDecoder.java b/src/org/apollo/net/release/r317/MagicOnNpcMessageDecoder.java index 4d8babcb..c631ac66 100644 --- a/src/org/apollo/net/release/r317/MagicOnNpcMessageDecoder.java +++ b/src/org/apollo/net/release/r317/MagicOnNpcMessageDecoder.java @@ -1,24 +1,28 @@ package org.apollo.net.release.r317; import org.apollo.game.message.impl.MagicOnNpcMessage; -import org.apollo.net.codec.game.*; +import org.apollo.net.codec.game.DataOrder; +import org.apollo.net.codec.game.DataTransformation; +import org.apollo.net.codec.game.DataType; +import org.apollo.net.codec.game.GamePacket; +import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.MagicOnNpcMessage} + * A {@link MessageDecoder} for the {@link MagicOnNpcMessage} * * @author Stuart */ public final class MagicOnNpcMessageDecoder extends MessageDecoder { - @Override - public MagicOnNpcMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); + @Override + public MagicOnNpcMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD); - int spellId = (int) reader.getSigned(DataType.SHORT, DataTransformation.ADD); + int index = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE, DataTransformation.ADD); + int spell = (int) reader.getUnsigned(DataType.SHORT, DataTransformation.ADD); - return new MagicOnNpcMessage(index, spellId); - } + return new MagicOnNpcMessage(index, spell); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/MagicOnPlayerMessageDecoder.java b/src/org/apollo/net/release/r317/MagicOnPlayerMessageDecoder.java index 81311901..2c393655 100644 --- a/src/org/apollo/net/release/r317/MagicOnPlayerMessageDecoder.java +++ b/src/org/apollo/net/release/r317/MagicOnPlayerMessageDecoder.java @@ -1,24 +1,28 @@ package org.apollo.net.release.r317; import org.apollo.game.message.impl.MagicOnPlayerMessage; -import org.apollo.net.codec.game.*; +import org.apollo.net.codec.game.DataOrder; +import org.apollo.net.codec.game.DataTransformation; +import org.apollo.net.codec.game.DataType; +import org.apollo.net.codec.game.GamePacket; +import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.MagicOnPlayerMessage} + * A {@link MessageDecoder} for the {@link MagicOnPlayerMessage} * * @author Stuart */ public final class MagicOnPlayerMessageDecoder extends MessageDecoder { - @Override - public MagicOnPlayerMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); + @Override + public MagicOnPlayerMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT, DataTransformation.ADD); - int spellId = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE); + int index = (int) reader.getUnsigned(DataType.SHORT, DataTransformation.ADD); + int spell = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE); - return new MagicOnPlayerMessage(index, spellId); - } + return new MagicOnPlayerMessage(index, spell); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/MouseClickedMessageDecoder.java b/src/org/apollo/net/release/r317/MouseClickedMessageDecoder.java index 70d40c7c..96de8f9e 100644 --- a/src/org/apollo/net/release/r317/MouseClickedMessageDecoder.java +++ b/src/org/apollo/net/release/r317/MouseClickedMessageDecoder.java @@ -7,26 +7,25 @@ import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.MouseClickedMessage} + * A {@link MessageDecoder} for the {@link MouseClickedMessage} * * @author Stuart */ public final class MouseClickedMessageDecoder extends MessageDecoder { - @Override - public MouseClickedMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); - int value = (int)reader.getUnsigned(DataType.INT); + @Override + public MouseClickedMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); + int value = (int) reader.getUnsigned(DataType.INT); - long delay = (value >> 20) * 50; + long delay = (value >> 20) * 50; + boolean right = ((value >> 19) & 0x1) == 1; - boolean rightMouseButton = ((value >> 19) & 0x1) == 1; + int cords = (value & 0x3FFFF); + int x = cords % 765; + int y = cords / 765; - int cords = (value & 0x3FFFF); - int x = cords % 765; - int y = cords / 765; - - return new MouseClickedMessage(delay, rightMouseButton, x, y); - } + return new MouseClickedMessage(delay, right, x, y); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/Release317.java b/src/org/apollo/net/release/r317/Release317.java index 24312f09..e1abf5d8 100644 --- a/src/org/apollo/net/release/r317/Release317.java +++ b/src/org/apollo/net/release/r317/Release317.java @@ -9,6 +9,7 @@ import org.apollo.game.message.impl.DisplayTabInterfaceMessage; import org.apollo.game.message.impl.EnterAmountMessage; import org.apollo.game.message.impl.ForwardPrivateChatMessage; import org.apollo.game.message.impl.FriendServerStatusMessage; +import org.apollo.game.message.impl.HintIconMessage; import org.apollo.game.message.impl.IdAssignmentMessage; import org.apollo.game.message.impl.IgnoreListMessage; import org.apollo.game.message.impl.LogoutMessage; @@ -126,11 +127,11 @@ public final class Release317 extends Release { register(53, new ItemOnItemMessageDecoder()); register(237, new MagicOnItemMessageDecoder()); - register(249, new MagicOnPlayerMessageDecoder()); + register(249, new MagicOnPlayerMessageDecoder()); register(3, new FocusUpdateMessageDecoder()); register(45, new FlaggedMouseEventMessageDecoder()); - register(241, new MouseClickedMessageDecoder()); + register(241, new MouseClickedMessageDecoder()); register(86, new ArrowKeyMessageDecoder()); register(95, new PrivacyOptionMessageDecoder()); @@ -145,11 +146,11 @@ public final class Release317 extends Release { register(155, new FirstNpcActionMessageDecoder()); register(72, new SecondNpcActionMessageDecoder()); - register(17, new ThirdNpcActionMessageDecoder()); + register(17, new ThirdNpcActionMessageDecoder()); register(21, new FourthNpcActionMessageDecoder()); - register(18, new FifthNpcActionMessageDecoder()); + register(18, new FifthNpcActionMessageDecoder()); - register(236, new TakeTileItemMessageDecoder()); + register(236, new TakeTileItemMessageDecoder()); register(192, new ItemOnObjectMessageDecoder()); register(128, new FirstPlayerActionMessageDecoder()); @@ -205,6 +206,6 @@ public final class Release317 extends Release { register(FriendServerStatusMessage.class, new FriendServerStatusMessageEncoder()); register(IgnoreListMessage.class, new IgnoreListMessageEncoder()); register(SendFriendMessage.class, new SendFriendMessageEncoder()); + register(HintIconMessage.class, new HintIconMessageEncoder()); } - } \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/FifthNpcActionMessageDecoder.java b/src/org/apollo/net/release/r377/FifthNpcActionMessageDecoder.java index 8cc8c0b1..13720043 100644 --- a/src/org/apollo/net/release/r377/FifthNpcActionMessageDecoder.java +++ b/src/org/apollo/net/release/r377/FifthNpcActionMessageDecoder.java @@ -8,7 +8,7 @@ import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.FifthNpcActionMessage}. + * A {@link MessageDecoder} for the {@link FifthNpcActionMessage}. * * @author Stuart */ @@ -17,7 +17,7 @@ public final class FifthNpcActionMessageDecoder extends MessageDecoder { + + @Override + public GamePacket encode(HintIconMessage message) { + GamePacketBuilder builder = new GamePacketBuilder(199); + int type = message.getType(); + builder.put(DataType.BYTE, type); + + switch (type) { + case HintIconMessage.NPC_TYPE: + case HintIconMessage.PLAYER_TYPE: + builder.put(DataType.SHORT, message.getIndex().get()); + break; + default: + throw new IllegalStateException("Unsupported hint icon type " + type + "."); + } + + return builder.toGamePacket(); + } + +} \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java b/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java index 6ee99adb..197a1aa8 100644 --- a/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java +++ b/src/org/apollo/net/release/r377/MagicOnNpcMessageDecoder.java @@ -1,11 +1,15 @@ package org.apollo.net.release.r377; import org.apollo.game.message.impl.MagicOnNpcMessage; -import org.apollo.net.codec.game.*; +import org.apollo.net.codec.game.DataOrder; +import org.apollo.net.codec.game.DataTransformation; +import org.apollo.net.codec.game.DataType; +import org.apollo.net.codec.game.GamePacket; +import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.MagicOnNpcMessage} + * A {@link MessageDecoder} for the {@link MagicOnNpcMessage} * * @author Stuart */ @@ -15,10 +19,10 @@ public final class MagicOnNpcMessageDecoder extends MessageDecoder { - @Override - public MagicOnPlayerMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); + @Override + public MagicOnPlayerMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); - int index = (int) reader.getSigned(DataType.SHORT, DataTransformation.ADD); - int spellId = (int) reader.getSigned(DataType.SHORT, DataOrder.LITTLE); + int index = (int) reader.getUnsigned(DataType.SHORT, DataTransformation.ADD); + int spell = (int) reader.getUnsigned(DataType.SHORT, DataOrder.LITTLE); - return new MagicOnPlayerMessage(index, spellId); - } + return new MagicOnPlayerMessage(index, spell); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/MouseClickedMessageDecoder.java b/src/org/apollo/net/release/r377/MouseClickedMessageDecoder.java index 5ee162ec..2a502c60 100644 --- a/src/org/apollo/net/release/r377/MouseClickedMessageDecoder.java +++ b/src/org/apollo/net/release/r377/MouseClickedMessageDecoder.java @@ -7,26 +7,25 @@ import org.apollo.net.codec.game.GamePacketReader; import org.apollo.net.release.MessageDecoder; /** - * A {@link org.apollo.net.release.MessageDecoder} for the {@link org.apollo.game.message.impl.MouseClickedMessage} + * A {@link MessageDecoder} for the {@link MouseClickedMessage} * * @author Stuart */ public final class MouseClickedMessageDecoder extends MessageDecoder { - @Override - public MouseClickedMessage decode(GamePacket packet) { - GamePacketReader reader = new GamePacketReader(packet); - int value = (int)reader.getUnsigned(DataType.INT); + @Override + public MouseClickedMessage decode(GamePacket packet) { + GamePacketReader reader = new GamePacketReader(packet); + int value = (int) reader.getUnsigned(DataType.INT); - long delay = (value >> 20) * 50; + long delay = (value >> 20) * 50; + boolean right = ((value >> 19) & 0x1) == 1; - boolean rightMouseButton = ((value >> 19) & 0x1) == 1; + int cords = (value & 0x3FFFF); + int x = cords % 765; + int y = cords / 765; - int cords = (value & 0x3FFFF); - int x = cords % 765; - int y = cords / 765; - - return new MouseClickedMessage(delay, rightMouseButton, x, y); - } + return new MouseClickedMessage(delay, right, x, y); + } } \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/Release377.java b/src/org/apollo/net/release/r377/Release377.java index 0681f56f..b2bc031d 100644 --- a/src/org/apollo/net/release/r377/Release377.java +++ b/src/org/apollo/net/release/r377/Release377.java @@ -9,6 +9,7 @@ import org.apollo.game.message.impl.DisplayTabInterfaceMessage; import org.apollo.game.message.impl.EnterAmountMessage; import org.apollo.game.message.impl.ForwardPrivateChatMessage; import org.apollo.game.message.impl.FriendServerStatusMessage; +import org.apollo.game.message.impl.HintIconMessage; import org.apollo.game.message.impl.IdAssignmentMessage; import org.apollo.game.message.impl.IgnoreListMessage; import org.apollo.game.message.impl.LogoutMessage; @@ -19,8 +20,8 @@ import org.apollo.game.message.impl.OpenInterfaceSidebarMessage; import org.apollo.game.message.impl.PlayerSynchronizationMessage; import org.apollo.game.message.impl.PositionMessage; import org.apollo.game.message.impl.PrivacyOptionMessage; -import org.apollo.game.message.impl.SectorChangeMessage; import org.apollo.game.message.impl.RemoveTileItemMessage; +import org.apollo.game.message.impl.SectorChangeMessage; import org.apollo.game.message.impl.SendFriendMessage; import org.apollo.game.message.impl.SendObjectMessage; import org.apollo.game.message.impl.ServerChatMessage; @@ -40,6 +41,7 @@ import org.apollo.game.message.impl.UpdateTileItemMessage; import org.apollo.game.message.impl.UpdateWeightMessage; import org.apollo.net.meta.PacketMetaDataGroup; import org.apollo.net.release.Release; +import org.apollo.net.release.r317.HintIconMessageEncoder; /** * A {@link Release} implementation for the 377 protocol. @@ -130,7 +132,7 @@ public final class Release377 extends Release { register(104, new MagicOnNpcMessageDecoder()); register(187, new FocusUpdateMessageDecoder()); - register(19, new MouseClickedMessageDecoder()); + register(19, new MouseClickedMessageDecoder()); register(171, new FlaggedMouseEventMessageDecoder()); register(140, new ArrowKeyMessageDecoder()); register(176, new PrivacyOptionMessageDecoder()); @@ -201,6 +203,7 @@ public final class Release377 extends Release { register(FriendServerStatusMessage.class, new FriendServerStatusMessageEncoder()); register(IgnoreListMessage.class, new IgnoreListMessageEncoder()); register(SendFriendMessage.class, new SendFriendMessageEncoder()); + register(HintIconMessage.class, new HintIconMessageEncoder()); } } \ No newline at end of file