From 1f1a2b3639ffd230c8fdc20f0a6b4e9e4e9105b4 Mon Sep 17 00:00:00 2001 From: Ryley Kimmel Date: Tue, 3 Mar 2015 15:02:17 -0500 Subject: [PATCH 1/3] Add wilderness area plugin. --- data/plugins/areas/plugin.xml | 1 + data/plugins/areas/wilderness.rb | 52 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 data/plugins/areas/wilderness.rb diff --git a/data/plugins/areas/plugin.xml b/data/plugins/areas/plugin.xml index 2c18bb32..0e9c4b1b 100644 --- a/data/plugins/areas/plugin.xml +++ b/data/plugins/areas/plugin.xml @@ -10,6 +10,7 @@ + diff --git a/data/plugins/areas/wilderness.rb b/data/plugins/areas/wilderness.rb new file mode 100644 index 00000000..27fcbd54 --- /dev/null +++ b/data/plugins/areas/wilderness.rb @@ -0,0 +1,52 @@ +require 'java' + +java_import 'org.apollo.game.model.entity.Player' +java_import 'org.apollo.game.message.impl.OpenOverlayMessage' +java_import 'org.apollo.game.message.impl.SetWidgetTextMessage' + + + +private + +MIN_X = 2945 +MIN_Y = 3522 +MAX_X = 3390 +MAX_Y = 3972 + +OVERLAY_INTERFACE_ID = 197 +LEVEL_STRING_ID = 199 + +declare_attribute(:wilderness_level, 0, :transient) + +# Determines the wilderness level for the specified player's position +def wilderness_level(player) + return (player.position.y - (MIN_Y - 1) / 8).ceil +end + +area_action :wilderness_level do + + on_entry do |player| + player.wilderness_level = wilderness_level(player) + player.interface_set.open_overlay(OVERLAY_INTERFACE_ID) + player.send(SetWidgetTextMessage.new(LEVEL_STRING_ID, "Level: #{player.wilderness_level}")) + show_action(ATTACK_ACTION) + end + + while_in do |player| + current = player.wilderness_level + updated = wilderness_level(player) + if (current != updated) + player.wilderness_level = updated + player.send(SetWidgetTextMessage.new(LEVEL_STRING_ID, "Level: #{player.wilderness_level}")) + end + end + + on_exit do |player| + player.wilderness_level = 0 + player.interface_set.close() # TODO: Will this cause issues with other potentially open interfaces? + hide_action(ATTACK_ACTION) + end + +end + +area :name => :wilderness, :coordinates => MIN_X, MIN_Y, MAX_X, MAX_Y, 0, => :actions => :wilderness_level \ No newline at end of file From 5c482766f248e745c67324794da1993f5a8f1942 Mon Sep 17 00:00:00 2001 From: Ryley Kimmel Date: Tue, 3 Mar 2015 18:20:08 -0500 Subject: [PATCH 2/3] Merge. --- data/plugins/navigation/door/constants.rb | 38 +++++++ data/plugins/navigation/door/door.rb | 31 ++++++ data/plugins/navigation/door/plugin.xml | 16 +++ data/plugins/navigation/door/util.rb | 99 +++++++++++++++++++ .../message/impl/RemoveObjectMessage.java | 76 ++++++++++++++ .../game/message/impl/SendObjectMessage.java | 16 ++- .../apollo/game/model/entity/GameObject.java | 7 +- .../apollo/net/release/r317/Release317.java | 2 + .../r317/RemoveObjectMessageEncoder.java | 25 +++++ .../r317/SendObjectMessageEncoder.java | 2 +- .../apollo/net/release/r377/Release377.java | 2 + .../r377/RemoveObjectMessageEncoder.java | 25 +++++ .../r377/SendObjectMessageEncoder.java | 2 +- .../net/release/r377/WalkMessageDecoder.java | 2 +- 14 files changed, 334 insertions(+), 9 deletions(-) create mode 100644 data/plugins/navigation/door/constants.rb create mode 100644 data/plugins/navigation/door/door.rb create mode 100644 data/plugins/navigation/door/plugin.xml create mode 100644 data/plugins/navigation/door/util.rb create mode 100644 src/org/apollo/game/message/impl/RemoveObjectMessage.java create mode 100644 src/org/apollo/net/release/r317/RemoveObjectMessageEncoder.java create mode 100644 src/org/apollo/net/release/r377/RemoveObjectMessageEncoder.java diff --git a/data/plugins/navigation/door/constants.rb b/data/plugins/navigation/door/constants.rb new file mode 100644 index 00000000..ec923218 --- /dev/null +++ b/data/plugins/navigation/door/constants.rb @@ -0,0 +1,38 @@ +java_import 'org.apollo.game.model.Direction' + +module DoorConstants + # TODO: GameObjectOrientation enumeration in Apollo's core? + module Orientation + WEST = 0 + NORTH = 1 + EAST = 2 + SOUTH = 3 + end + + # The object size of a door. + DOOR_SIZE = 1 + + # Door object ids that have a hinge on the left side. + LEFT_SIDE_HINGE_DOOR_IDS = [1516, 1536, 1533] + + # Door object ids that have a hinge on the right side. + RIGHT_SIDE_HINGE_DOOR_IDS = [1519, 1530, 4465, 4467, 3014, 3017, 3018, 3019] + + # A map of orientations that a door will translate to when opened. + ORIENTATIONS = { + # Orientations for doors that have a hinge on the left side. + :left_side_hinge => { + Orientation::NORTH => Orientation::WEST, + Orientation::SOUTH => Orientation::EAST, + Orientation::WEST => Orientation::SOUTH, + Orientation::EAST => Orientation::NORTH + }, + # Orientations for doors that have a hinge on the right side. + :right_side_hinge => { + Orientation::NORTH => Orientation::EAST, + Orientation::SOUTH => Orientation::WEST, + Orientation::WEST => Orientation::NORTH, + Orientation::EAST => Orientation::SOUTH + } + } +end \ No newline at end of file diff --git a/data/plugins/navigation/door/door.rb b/data/plugins/navigation/door/door.rb new file mode 100644 index 00000000..7ee1af49 --- /dev/null +++ b/data/plugins/navigation/door/door.rb @@ -0,0 +1,31 @@ +java_import 'org.apollo.game.action.DistancedAction' + +# A distanced action which opens a door. +class OpenDoorAction < DistancedAction + include DoorConstants + + attr_reader :door_object + + def initialize(mob, door_object) + super(0, true, mob, door_object.position, DOOR_SIZE) + @door_object = door_object + end + + def executeAction + mob.turn_to @door_object.position + DoorUtil::toggle(@door_object, mob) + stop + end + + def equals(other) + return (get_class == other.get_class && @position == other.position) + end +end + +# Message handler for opening and closing doors. +on :message, :first_object_action do |ctx, player, message| + if DoorUtil::is_door?(message.id) + door_object = DoorUtil::get_door_object(message.position, message.id) + player.start_action(OpenDoorAction.new(player, door_object)) unless door_object.nil? + end +end \ No newline at end of file diff --git a/data/plugins/navigation/door/plugin.xml b/data/plugins/navigation/door/plugin.xml new file mode 100644 index 00000000..4b5f435f --- /dev/null +++ b/data/plugins/navigation/door/plugin.xml @@ -0,0 +1,16 @@ + + + door + 1 + Doors + Adds support for doors throughout the game. + + Shiver + + + + + + + + \ No newline at end of file diff --git a/data/plugins/navigation/door/util.rb b/data/plugins/navigation/door/util.rb new file mode 100644 index 00000000..33d35725 --- /dev/null +++ b/data/plugins/navigation/door/util.rb @@ -0,0 +1,99 @@ +java_import 'org.apollo.game.model.entity.GameObject' +java_import 'org.apollo.game.model.entity.Entity' +java_import 'org.apollo.game.model.Position' +java_import 'org.apollo.game.message.impl.PositionMessage' +java_import 'org.apollo.game.message.impl.RemoveObjectMessage' +java_import 'org.apollo.game.message.impl.SendObjectMessage' + +module DoorUtil + include DoorConstants + + # A hash containing currently toggled door objects mapped to the original door objects. + TOGGLED_DOOR_REPOSITORY = {} + + # Translates a door's position in the direction of its orientation. + def self.translate_door_position(door) + position = door.position + orientation = door.orientation + case orientation + when Orientation::WEST + return Position.new(position.x - 1, position.y, position.height) + when Orientation::EAST + return Position.new(position.x + 1, position.y, position.height) + when Orientation::NORTH + return Position.new(position.x, position.y + 1, position.height) + when Orientation::SOUTH + return Position.new(position.x, position.y - 1, position.height) + end + raise 'Invalid orientation for door!' + end + + # Translates the orientation of a door to a toggled position. + def self.translate_door_orientation(door) + object_id = door.id + orientation = door.orientation + if RIGHT_SIDE_HINGE_DOOR_IDS.include?(object_id) + return ORIENTATIONS[:right_side_hinge][orientation] + elsif LEFT_SIDE_HINGE_DOOR_IDS.include?(object_id) + return ORIENTATIONS[:left_side_hinge][orientation] + end + raise 'Given object was not registered as a door!' + end + + # Replaces a door object for a given player. + # TODO: This is temporary. + def self.replace_door(player, original, new) + player.send PositionMessage.new(player.last_known_sector, original.position) + player.send RemoveObjectMessage.new(original) + player.send PositionMessage.new(player.last_known_sector, new.position) + player.send SendObjectMessage.new(new) + end + + # Toggles the given door. + def self.toggle(door, player) + # First, we remove the door we're toggling (or un-toggling) from the game world. + position = door.position + sector = $world.sector_repository.from_position(position) + sector.remove_entity door + + # Have we toggled this door already? + if TOGGLED_DOOR_REPOSITORY.include?(door) + # If we have, we get our original door. This also deletes the entry from our repository. + original_door = TOGGLED_DOOR_REPOSITORY.delete(door) + + # Now we add our new door to the game world. + original_sector = $world.sector_repository.from_position(original_door.position) + original_sector.add_entity original_door + + # TODO: This and the 'player' parameter are temporary. We still need to synchronize objects for local players. + replace_door player, door, original_door + else + # If not, we get the translated orientation and position for this door, and create a new game object. + toggled_position = translate_door_position(door) + toggled_orientation = translate_door_orientation(door) + toggled_door = GameObject.new(door.id, toggled_position, door.type, toggled_orientation) + + # Now we add our new door to the game world. + toggled_sector = $world.sector_repository.from_position(toggled_position) + toggled_sector.add_entity toggled_door + + # Insert our toggled door in the repository. + TOGGLED_DOOR_REPOSITORY[toggled_door] = door + + # TODO: This and the 'player' parameter are temporary. We still need to synchronize objects for local players. + replace_door player, door, toggled_door + end + end + + # Gets the door object at the given position, if it exists. + def self.get_door_object(position, object_id) + game_objects = $world.sector_repository.from_position(position).get_entities(position, EntityType::GAME_OBJECT) + game_objects.each { |game_object| return game_object if game_object.get_id == object_id } + return nil + end + + # Checks if the given game object id is a door. + def self.is_door?(object_id) + RIGHT_SIDE_HINGE_DOOR_IDS.include?(object_id) || LEFT_SIDE_HINGE_DOOR_IDS.include?(object_id) + end +end \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/RemoveObjectMessage.java b/src/org/apollo/game/message/impl/RemoveObjectMessage.java new file mode 100644 index 00000000..910b96fd --- /dev/null +++ b/src/org/apollo/game/message/impl/RemoveObjectMessage.java @@ -0,0 +1,76 @@ +package org.apollo.game.message.impl; + +import org.apollo.game.message.Message; +import org.apollo.game.model.entity.GameObject; + +/** + * A {@link Message} sent to the client to remove an object from a tile. + * + * @author Major + */ +public final class RemoveObjectMessage extends Message { + + /** + * The orientation of the object. + */ + private final int orientation; + + /** + * The position of the object. + */ + private final int positionOffset; + + /** + * The type of the object. + */ + private final int type; + + /** + * Creates the RemoveObjectMessage. + * + * @param object The {@link GameObject} to send. + */ + public RemoveObjectMessage(GameObject object) { + this(object, 0); + } + + /** + * Creates the RemoveObjectMessage. + * + * @param object The {@link GameObject} to send. + * @param positionOffset The offset of the object's position from the sector's central position. + */ + public RemoveObjectMessage(GameObject object, int positionOffset) { + this.positionOffset = positionOffset; + this.type = object.getType(); + this.orientation = object.getOrientation(); + } + + /** + * Gets the orientation of the object. + * + * @return The orientation. + */ + public int getOrientation() { + return orientation; + } + + /** + * Gets the position offset of the object. + * + * @return The position offset. + */ + public int getPositionOffset() { + return positionOffset; + } + + /** + * Gets the orientation of the object. + * + * @return The type. + */ + public int getType() { + return type; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/message/impl/SendObjectMessage.java b/src/org/apollo/game/message/impl/SendObjectMessage.java index da40741d..02c4b216 100644 --- a/src/org/apollo/game/message/impl/SendObjectMessage.java +++ b/src/org/apollo/game/message/impl/SendObjectMessage.java @@ -31,15 +31,25 @@ public final class SendObjectMessage extends Message { private final int type; /** - * Creates the send object message. + * Creates the SendObjectMessage. * * @param object The {@link GameObject} to send. */ public SendObjectMessage(GameObject object) { + this(object, 0); + } + + /** + * Creates the SendObjectMessage. + * + * @param object The {@link GameObject} to send. + * @param positionOffset The offset of the object's position from the sector's central position. + */ + public SendObjectMessage(GameObject object, int positionOffset) { this.id = object.getId(); - this.positionOffset = 0; + this.positionOffset = positionOffset; this.type = object.getType(); - this.orientation = object.getRotation(); + this.orientation = object.getOrientation(); } /** diff --git a/src/org/apollo/game/model/entity/GameObject.java b/src/org/apollo/game/model/entity/GameObject.java index 8592c7a1..958383cd 100644 --- a/src/org/apollo/game/model/entity/GameObject.java +++ b/src/org/apollo/game/model/entity/GameObject.java @@ -28,7 +28,7 @@ public final class GameObject extends Entity { */ public GameObject(int id, Position position, int type, int orientation) { super(position); - this.packed = id << 8 | type << 2 | orientation; + this.packed = id << 8 | (type & 0x3F) << 2 | orientation & 0x3; } @Override @@ -69,7 +69,7 @@ public final class GameObject extends Entity { * * @return The orientation. */ - public int getRotation() { + public int getOrientation() { return packed & 0x3; } @@ -89,7 +89,8 @@ public final class GameObject extends Entity { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType()).add("rotation", getRotation()).toString(); + return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType()).add("orientation", getOrientation()) + .toString(); } } \ 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 39c77ab4..54d16065 100644 --- a/src/org/apollo/net/release/r317/Release317.java +++ b/src/org/apollo/net/release/r317/Release317.java @@ -24,6 +24,7 @@ import org.apollo.game.message.impl.OpenSidebarMessage; 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.RemoveObjectMessage; import org.apollo.game.message.impl.RemoveTileItemMessage; import org.apollo.game.message.impl.SectorChangeMessage; import org.apollo.game.message.impl.SendFriendMessage; @@ -206,6 +207,7 @@ public final class Release317 extends Release { register(UpdateTileItemMessage.class, new UpdateTileItemMessageEncoder()); register(RemoveTileItemMessage.class, new RemoveTileItemMessageEncoder()); register(SendObjectMessage.class, new SendObjectMessageEncoder()); + register(RemoveObjectMessage.class, new RemoveObjectMessageEncoder()); register(ForwardPrivateChatMessage.class, new ForwardPrivateChatMessageEncoder()); register(FriendServerStatusMessage.class, new FriendServerStatusMessageEncoder()); diff --git a/src/org/apollo/net/release/r317/RemoveObjectMessageEncoder.java b/src/org/apollo/net/release/r317/RemoveObjectMessageEncoder.java new file mode 100644 index 00000000..bf86a1a9 --- /dev/null +++ b/src/org/apollo/net/release/r317/RemoveObjectMessageEncoder.java @@ -0,0 +1,25 @@ +package org.apollo.net.release.r317; + +import org.apollo.game.message.impl.RemoveObjectMessage; +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.GamePacketBuilder; +import org.apollo.net.release.MessageEncoder; + +/** + * A {@link MessageEncoder} for the {@link RemoveObjectMessage}. + * + * @author Major + */ +public final class RemoveObjectMessageEncoder extends MessageEncoder { + + @Override + public GamePacket encode(RemoveObjectMessage message) { + GamePacketBuilder builder = new GamePacketBuilder(101); + builder.put(DataType.BYTE, DataTransformation.NEGATE, message.getType() << 2 | message.getOrientation()); + builder.put(DataType.BYTE, message.getPositionOffset()); + return builder.toGamePacket(); + } + +} \ No newline at end of file diff --git a/src/org/apollo/net/release/r317/SendObjectMessageEncoder.java b/src/org/apollo/net/release/r317/SendObjectMessageEncoder.java index 67cf38c6..4a815aee 100644 --- a/src/org/apollo/net/release/r317/SendObjectMessageEncoder.java +++ b/src/org/apollo/net/release/r317/SendObjectMessageEncoder.java @@ -20,7 +20,7 @@ public final class SendObjectMessageEncoder extends MessageEncoder { + + @Override + public GamePacket encode(RemoveObjectMessage message) { + GamePacketBuilder builder = new GamePacketBuilder(88); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, message.getPositionOffset()); + builder.put(DataType.BYTE, DataTransformation.SUBTRACT, message.getType() << 2 | message.getOrientation()); + return builder.toGamePacket(); + } + +} \ No newline at end of file diff --git a/src/org/apollo/net/release/r377/SendObjectMessageEncoder.java b/src/org/apollo/net/release/r377/SendObjectMessageEncoder.java index 533534c3..69d7e1a8 100644 --- a/src/org/apollo/net/release/r377/SendObjectMessageEncoder.java +++ b/src/org/apollo/net/release/r377/SendObjectMessageEncoder.java @@ -18,7 +18,7 @@ public final class SendObjectMessageEncoder extends MessageEncoder { return new WalkMessage(positions, run); } -} +} \ No newline at end of file From a68502637a1fde910ba561295d6026dc6ca76346 Mon Sep 17 00:00:00 2001 From: Ryley Kimmel Date: Tue, 3 Mar 2015 18:20:38 -0500 Subject: [PATCH 3/3] Use square brackets for arrays in wilderness plugin. --- data/plugins/areas/wilderness.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/plugins/areas/wilderness.rb b/data/plugins/areas/wilderness.rb index 27fcbd54..746c5e4f 100644 --- a/data/plugins/areas/wilderness.rb +++ b/data/plugins/areas/wilderness.rb @@ -49,4 +49,4 @@ area_action :wilderness_level do end -area :name => :wilderness, :coordinates => MIN_X, MIN_Y, MAX_X, MAX_Y, 0, => :actions => :wilderness_level \ No newline at end of file +area :name => :wilderness, :coordinates => [ MIN_X, MIN_Y, MAX_X, MAX_Y, 0 ], :actions => :wilderness_level \ No newline at end of file