package com.asteria.net.message; import java.util.Objects; import com.asteria.game.NodeType; import com.asteria.game.World; import com.asteria.game.character.CharacterNode; import com.asteria.game.character.player.Player; import com.asteria.game.item.Item; import com.asteria.game.item.ItemNode; import com.asteria.game.location.Palette; import com.asteria.game.location.PaletteTile; import com.asteria.game.location.Position; import com.asteria.game.object.ObjectDirection; import com.asteria.game.object.ObjectNode; import com.asteria.game.object.ObjectType; import com.asteria.net.ByteOrder; import com.asteria.net.ValueType; import com.google.common.base.Preconditions; /** * The utility class used to queue {@link MessageBuilder}s to be encoded and * written to the Client. * * @author lare96 <http://github.com/lare96> */ public final class OutputMessages { /** * The player that will queue these messages. */ private final Player player; /** * Creates a new {@link OutputMessages}. * * @param player * the player that will queue these messages. */ public OutputMessages(Player player) { this.player = player; } /** * The message that forces the player to view {@code id} tab. * * @param id * the tab to force on the player. * @return an instance of this encoder. */ public OutputMessages sendForceTab(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(106); msg.put(id, ValueType.C); player.getSession().queue(msg); return this; } /** * The message that either shows or hides a layer on an interface. * * @param id * the interface to show or hide a layer on. * @param hide * if the layer should be hidden or shown. * @return an instance of this encoder. */ public OutputMessages sendInterfaceLayer(int id, boolean hide) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(171); msg.put(hide ? 1 : 0); msg.putShort(id); player.getSession().queue(msg); return this; } /** * The message that updates a special bar with {@code amount} of special * energy. * * @param id * the special bar to update with energy. * @param amount * the amount of energy to update a special bar with. * @return an instance of this encoder. */ public OutputMessages sendUpdateSpecial(int id, int amount) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(70); msg.putShort(amount); msg.putShort(0, com.asteria.net.ByteOrder.LITTLE); msg.putShort(id, com.asteria.net.ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The messages that display {@code str} on an empty chatbox. * * @param str * the string to display on the chatbox. * @return an instance of this encoder. */ public OutputMessages sendChatboxString(String str) { sendString(str, 357); sendString("Click here to continue", 358); sendChatInterface(356); return this; } /** * The messages that play an animation for an object that only the * underlying player can see. * * @param position * the position the object is on. * @param animation * the animation to play for this object. * @param type * the object type of the object. * @param direction * the direction this object is facing. * @return an instance of this encoder. */ public OutputMessages sendObjectAnimation(Position position, int animation, ObjectType type, ObjectDirection direction) { sendCoordinates(position); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(160); msg.put(((0 & 7) << 4) + (0 & 7), ValueType.S); msg.put((type.getId() << 2) + (direction.getId() & 3), ValueType.S); msg.putShort(animation, ValueType.A); player.getSession().queue(msg); return this; } /** * The messages that play an animation for an object that all local players * can see. * * @param position * the position the object is on. * @param animation * the animation to play for this object. * @param type * the object type of the object. * @param direction * the direction this object is facing. * @return an instance of this encoder. */ public OutputMessages sendLocalObjectAnimation(Position position, int animation, ObjectType type, ObjectDirection direction) { player.getMessages().sendObjectAnimation(position, animation, type, direction); player.getLocalPlayers().stream().filter(Objects::nonNull).forEach( p -> p.getMessages().sendObjectAnimation(position, animation, type, direction)); return this; } /** * The message that creates a graphic that only the underlying player can * see. * * @param id * the id of the graphic that will be created. * @param position * the position of the graphic that will be created. * @param level * the height of the graphic that will be created. * @return an instance of this encoder. */ public OutputMessages sendGraphic(int id, Position position, int level) { sendCoordinates(position); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(4); msg.put(0); msg.putShort(id); msg.put(level); msg.putShort(0); player.getSession().queue(msg); return this; } /** * The message that creates a graphic that all local players can see. * * @param id * the id of the graphic that will be created. * @param position * the position of the graphic that will be created. * @param level * the height of the graphic that will be created. * @return an instance of this encoder. */ public OutputMessages sendLocalGraphic(int id, Position position, int level) { player.getMessages().sendGraphic(id, position, level); player.getLocalPlayers().stream().filter(Objects::nonNull).forEach(p -> p.getMessages().sendGraphic(id, position, level)); return this; } /** * The message that creates a graphic that all players can see. * * @param id * the id of the graphic that will be created. * @param position * the position of the graphic that will be created. * @param level * the height of the graphic that will be created. * @return an instance of this encoder. */ public static void sendAllGraphic(int id, Position position, int level) { World.getPlayers().forEach(p -> p.getMessages().sendGraphic(id, position, level)); } /** * The message that will play a sound for the underlying player. * * @param id * the id of the sound that will be played. * @param type * the type of sound that will be played. * @param delay * the delay before the sound will be played. * @return an instance of this encoder. */ public OutputMessages sendSound(int id, int type, int delay) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(174); msg.putShort(id); msg.put(type); msg.putShort(delay); player.getSession().queue(msg); return this; } /** * The message that will play a sound for all of the local players. * * @param id * the id of the sound that will be played. * @param type * the type of sound that will be played. * @param delay * the delay before the sound will be played. * @return an instance of this encoder. */ public OutputMessages sendLocalSound(int id, int type, int delay) { player.getMessages().sendSound(id, type, delay); player.getLocalPlayers().stream().filter(Objects::nonNull).forEach(p -> p.getMessages().sendSound(id, type, delay)); return this; } /** * The message that allows for an interface to be animated. * * @param id * the interface to animate on. * @param animation * the animation to animate the interface with. * @return an instance of this encoder. */ public OutputMessages sendInterfaceAnimation(int id, int animation) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(200); msg.putShort(id); msg.putShort(animation); player.getSession().queue(msg); return this; } /** * The message that updates the state of the multi-combat icon. * * @param hide * determines if the icon should be turned on or off. * @return an instance of this encoder. */ public OutputMessages sendMultiIcon(boolean hide) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(61); msg.put(hide ? 0 : 1); player.getSession().queue(msg); return this; } /** * The message that sends {@code item} on a specific interface slot. * * @param id * the interface to display the item on. * @param item * the item to display on the interface. * @param slot * the slot on the interface to display the item on. * @return an instance of this encoder. */ public OutputMessages sendItemOnInterfaceSlot(int id, Item item, int slot) { MessageBuilder msg = MessageBuilder.create(); msg.newVarShortMessage(34); msg.putShort(id); msg.put(slot); msg.putShort(item.getId() + 1); if (item.getAmount() > 254) { msg.put(255); msg.putShort(item.getAmount()); } else { msg.put(item.getAmount()); } msg.endVarShortMessage(); player.getSession().queue(msg); return this; } /** * The message that sends an item model on an interface. * * @param id * the interface id to send the model on. * @param zoom * the zoom of the model that will be sent. * @param model * the item model that will be sent on the interface, or in other * words the item identification. * @return an instance of this encoder. */ public OutputMessages sendItemModelOnInterface(int id, int zoom, int model) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(246); msg.putShort(id, com.asteria.net.ByteOrder.LITTLE); msg.putShort(zoom).putShort(model); player.getSession().queue(msg); return this; } /** * The message that sends an array of items on an interface. * * @param id * the interface that the items will be sent on. * @param items * the items that will be sent on the interface. * @param length * the amount of items that will be sent on the interface. * @return an instance of this encoder. */ public OutputMessages sendItemsOnInterface(int id, Item[] items, int length) { MessageBuilder msg = MessageBuilder.create(); msg.newVarShortMessage(53).putShort(id); if (items == null) { msg.putShort(0); msg.put(0); msg.putShort(0, com.asteria.net.ValueType.A, com.asteria.net.ByteOrder.LITTLE); msg.endVarShortMessage(); player.getSession().queue(msg); return this; } msg.putShort(length); for (Item item : items) { if (item != null) { if (item.getAmount() > 254) { msg.put(255); msg.putInt(item.getAmount(), com.asteria.net.ByteOrder.INVERSE_MIDDLE); } else { msg.put(item.getAmount()); } msg.putShort(item.getId() + 1, com.asteria.net.ValueType.A, com.asteria.net.ByteOrder.LITTLE); } else { msg.put(0); msg.putShort(0, com.asteria.net.ValueType.A, com.asteria.net.ByteOrder.LITTLE); } } msg.endVarShortMessage(); player.getSession().queue(msg); return this; } /** * The message that sends an array of items on an interface, with the length * being the capacity of {@code items}. * * @param id * the interface that the items will be sent on. * @param items * the items that will be sent on the interface. * @return an instance of this encoder. */ public OutputMessages sendItemsOnInterface(int id, Item[] items) { int length = (items == null) ? 0 : items.length; return sendItemsOnInterface(id, items, length); } /** * The message that sends the head model of an NPC to an interface. * * @param id * the interface to send the model on. * @param model * the NPC model that will be sent on the interface, or in other * words the NPC identification. * @return an instance of this encoder. */ public OutputMessages sendNpcModelOnInterface(int id, int model) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(75); msg.putShort(model, ValueType.A, ByteOrder.LITTLE); msg.putShort(id, ValueType.A, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that creates a custom map region made up tiles from other * regions. * * @param palette * the tiles to construct into a region. * @return an instance of this encoder. */ public OutputMessages sendCustomMapRegion(Palette palette) { sendMapRegion(); MessageBuilder msg = MessageBuilder.create(); msg.newVarShortMessage(241); msg.putShort(player.getPosition().getRegionY() + 6, ValueType.A); msg.startBitAccess(); for (int z = 0; z < 4; z++) { for (int x = 0; x < 13; x++) { for (int y = 0; y < 13; y++) { PaletteTile tile = palette.getTile(x, y, z); msg.putBits(1, tile != null ? 1 : 0); if (tile != null) msg.putBits(26, tile.getX() << 14 | tile.getY() << 3 | tile.getZ() << 24 | tile.getRotation() << 1); } } } msg.endBitAccess(); msg.putShort(player.getPosition().getRegionX() + 6); msg.endVarShortMessage(); player.getSession().queue(msg); return this; } /** * The message that sends the head model of a player to an interface. * * @param id * the interface to send the model on. * @return an instance of this encoder. */ public OutputMessages sendPlayerModelOnInterface(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(185); msg.putShort(id, ValueType.A, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that causes a sidebar icon to start flashing. * * @param code * the identification of the sidebar to flash. The code for each * of the sidebar icons are as follows: * <p> * <p> * Attack type: 0 * <p> * Stats: -1 * <p> * Quests: -2 * <p> * Inventory: -3 * <p> * Wearing: -4 * <p> * Prayer: -5 * <p> * Magic: -6 * <p> * Empty: -7 * <p> * Friends list: -8 * <p> * Ignore list: -9 * <p> * Log out: -10 * <p> * Settings: -11 * <p> * Emotes: -12 * <p> * Music: -13 * <p> * <p> * @return an instance of this encoder. */ public OutputMessages sendFlashSidebar(int code) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(24); msg.put(code, ValueType.A); player.getSession().queue(msg); return this; } /** * The message that displays the "Enter name" interface. * * @return an instance of this encoder. */ public OutputMessages sendEnterName() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(187); player.getSession().queue(msg); return this; } /** * The message that changes the state of the minimap. * * @param code * the new state of the minimap. The code for each of the minimap * states are as follows: * <p> * <p> * Normal: 0 * <p> * Normal, but unclickable: 1 * <p> * Blacked out: 2 * <p> * <p> * @return an instance of this encoder. */ public OutputMessages sendMinimapState(int code) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(99); msg.put(code); player.getSession().queue(msg); return this; } /** * The message that resets the camera's angle. * * @return an instance of this encoder. */ public OutputMessages sendResetCameraAngle() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(108); player.getSession().queue(msg); return this; } /** * The message that sends the camera angle. There isn't much documentation * out there on what the values actually represent. * * @param x * the {@code X} coordinate within the region. * @param y * the {@code Y} coordinate within the region. * @param level * the level of the camera from the ground. * @param speed * how fast the camera will turn to the angle. * @param angle * the angle the camera will turn to. * @return an instance of this encoder. */ public OutputMessages sendCameraAngle(int x, int y, int level, int speed, int angle) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(177); msg.put(x / 64); msg.put(y / 64); msg.putShort(level); msg.put(speed); msg.put(angle); player.getSession().queue(msg); return this; } /** * The message that moves the actual camera. There isn't much documentation * out there on what the values actually represent. * * @param x * the {@code X} coordinate within the region. * @param y * the {@code Y} coordinate within the region. * @param z * the {@code Z} coordinate within the region. * @param speed * how fast the camera will move. * @param angle * the angle the camera will turn to while moving. * @return an instance of this encoder. */ public OutputMessages sendCameraMovement(int x, int y, int z, int speed, int angle) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(166); msg.put(x / 64); msg.put(y / 64); msg.putShort(z); msg.put(speed); msg.put(angle); player.getSession().queue(msg); return this; } /** * The message that causes the screen and camera to shake. * * @param parameter * the position parameter to oscillate. The position parameters * are as follows: * <p> * <p> * Camera location along world X axis (a horizontal axis, aligned * with map grid X): 0 * <p> * Camera location along world Z axis (vertical axis): 1 * <p> * Camera location along world Y axis (a horizontal axis, aligned * with map grid Y): 2 * <p> * Camera orientation in world X plane w.r.t. world Z axis, i.e. * yaw: 3 * <p> * Camera orientation in world Z plane w.r.t. world X axis, i.e. * pitch: 4 * <p> * <p> * @param jitter * the amount of randomization in the screen shake. * @param amplitude * the maximum extent of the shake. * @param frequency * how often the screen will shake (scaled by 100). * @return an instance of this encoder. */ public OutputMessages sendCameraShake(int parameter, int jitter, int amplitude, int frequency) { Preconditions.checkArgument(parameter <= 4); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(35); msg.put(parameter); msg.put(jitter); msg.put(amplitude); msg.put(frequency); player.getSession().queue(msg); return this; } /** * The message that resets the position of the camera. * * @return an instance of this encoder. */ public OutputMessages sendResetCameraPosition() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(107); player.getSession().queue(msg); return this; } /** * The message that plays music for the underlying player. * * @param id * the identification of the music to play. * @return an instance of this encoder. */ public OutputMessages sendMusic(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(74); msg.putShort(id, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that sends the system update timer. A timer showing how many * seconds until a 'System Update' will appear in the lower left hand corner * of the game screen. After the timer reaches 0 all players are * disconnected and are unable to log in again until server is restarted. * Players connecting will receive a message stating, * "The server is being updated. Please wait 1 minute and try again." * (unless stated otherwise). * * @param amount * the amount of time until an update. * @return an instance of this encoder. */ public OutputMessages sendSystemUpdate(int amount) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(114); msg.putShort(amount, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that sends the underlying player's run energy percentage to * the correct place. * * @return an instance of this encoder. */ public OutputMessages sendRunEnergy() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(110); msg.put(player.getRunEnergy().get()); player.getSession().queue(msg); return this; } /** * The message that changes the color of an interface that is text. * * @param id * the interface identification to send the color on. * @param color * the new color that will be added to the interface. The color * hex codes are as follows: * <p> * <p> * Red: 0x6000 * <p> * Yellow: 0x33FF66 * <p> * Green: 0x3366 * <p> * <p> * @return an instance of this encoder. */ public OutputMessages sendInterfaceColor(int id, int color) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(122); msg.putShort(id, ValueType.A, ByteOrder.LITTLE); msg.putShort(color, ValueType.A, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that launches a projectile that only the underlying player * can see. * * @param position * the position of the projectile. * @param offset * the offset position of the projectile. * @param angle * the angle of the projectile. * @param speed * the speed of the projectile. * @param gfxMoving * the rate that projectile gfx moves in. * @param startHeight * the starting height of the projectile. * @param endHeight * the ending height of the projectile. * @param lockon * the lockon value of this projectile. * @param time * the time it takes for this projectile to hit its desired * position. * @return an instance of this encoder. */ public OutputMessages sendProjectile(Position position, Position offset, int angle, int speed, int gfxMoving, int startHeight, int endHeight, int lockon, int time) { sendCoordinates(position); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(117); msg.put(angle); msg.put(offset.getY()); msg.put(offset.getX()); msg.putShort(lockon); msg.putShort(gfxMoving); msg.put(startHeight); msg.put(endHeight); msg.putShort(time); msg.putShort(speed); msg.put(16); msg.put(64); player.getSession().queue(msg); return this; } /** * The message that launches a projectile that all of the local players can * see. * * @param position * the position of the projectile. * @param offset * the offset position of the projectile. * @param angle * the angle of the projectile. * @param speed * the speed of the projectile. * @param gfxMoving * the rate that projectile gfx moves in. * @param startHeight * the starting height of the projectile. * @param endHeight * the ending height of the projectile. * @param lockon * the lockon value of this projectile. * @param time * the time it takes for this projectile to hit its desired * position. * @return an instance of this encoder. */ public void sendAllProjectile(Position position, Position offset, int angle, int speed, int gfxMoving, int startHeight, int endHeight, int lockon, int time) { player.getLocalPlayers().stream().filter(Objects::nonNull).forEach( p -> p.getMessages().sendProjectile(position, offset, angle, speed, gfxMoving, startHeight, endHeight, lockon, time)); } /** * The message that changes the configuration value for a certain client * setting in the form of a byte. * * @param id * the setting identification number. * @param state * the new value for the setting. * @return an instance of this encoder. */ public OutputMessages sendByteState(int id, int state) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(36); msg.putShort(id, ByteOrder.LITTLE); msg.put(state); player.getSession().queue(msg); return this; } /** * The message that changes the configuration value for a certain client * setting in the form of an integer. * * @param id * the setting identification number. * @param state * the new value for the setting. * @return an instance of this encoder. */ public OutputMessages sendIntState(int id, int state) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(87); msg.putShort(id, ByteOrder.LITTLE); msg.putInt(state, ByteOrder.MIDDLE); player.getSession().queue(msg); return this; } /** * The message that spawns an object only the underlying player can see. * * @param object * the object to spawn for the player. * @return an instance of this encoder. */ public OutputMessages sendObject(ObjectNode object) { sendCoordinates(object.getPosition()); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(151); msg.put(0, ValueType.S); msg.putShort(object.getId(), ByteOrder.LITTLE); msg.put((object.getObjectType().getId() << 2) + (object.getDirection().getId() & 3), ValueType.S); player.getSession().queue(msg); return this; } /** * The message that removes an object only the underlying player can see. * * @param position * the position of the object to remove for the player. * @return an instance of this encoder. */ public OutputMessages sendRemoveObject(Position position) { sendCoordinates(position); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(101); msg.put((ObjectType.DEFAULT.getId() << 2) + (ObjectDirection.SOUTH.getId() & 3), ValueType.C); msg.put(0); player.getSession().queue(msg); return this; } /** * The messages that replace an existing object with a new one. * * @param position * the position that the old object is in. * @param object * the new object to take its place. * @return an instance of this encoder. */ public OutputMessages sendReplaceObject(Position position, int object) { sendRemoveObject(position); sendObject(new ObjectNode(object, position, ObjectDirection.SOUTH)); return this; } /** * The message that sends the underlying player's skill to the proper * interfaces. * * @param id * the identification number of the skill. * @param level * the level reached in this skill. * @param exp * the amount of experience obtained in this skill. * @return an instance of this encoder. */ public OutputMessages sendSkill(int id, int level, int exp) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(134).put(id).putInt(exp, ByteOrder.MIDDLE).put(level); player.getSession().queue(msg); return this; } /** * The message that closes any interfaces the underlying player has open. * * @return an instance of this encoder. */ public OutputMessages sendCloseWindows() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(219); player.getSession().queue(msg); player.getDialogueChain().interrupt(); return this; } /** * The message that sends the first private messaging list load status. * * @param code * the status of the friends list. The status for the friends * lists are as follows: * <p> * <p> * Loading: 0 * <p> * Connecting: 1 * <p> * Loaded: 2 * <p> * <p> * @return an instance of this encoder. */ public OutputMessages sendPrivateMessageListStatus(int code) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(221); msg.put(code); player.getSession().queue(msg); return this; } /** * The message that sends a player to the friend list. * * @param name * the player's name to add to the list. * @param online * if the player is online or not. * @return an instance of this encoder. */ public OutputMessages sendPrivateMessageFriend(long name, boolean online) { int value = online ? 1 : 0; if (value != 0) value += 9; MessageBuilder msg = MessageBuilder.create(); msg.newMessage(50); msg.putLong(name); msg.put(value); player.getSession().queue(msg); return this; } /** * The message that sends a hint arrow on a position. * * @param position * the position to send the arrow on. * @param direction * the direction on the position to send the arrow on. The * possible directions to put the arrow on are as follows: * <p> * <p> * Middle: 2 * <p> * West: 3 * <p> * East: 4 * <p> * South: 5 * <p> * North: 6 * <p> * <p> * @return an instance of this encoder. */ public OutputMessages sendPositionHintArrow(Position position, int direction) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(254); msg.put(direction); msg.putShort(position.getX()); msg.putShort(position.getY()); msg.put(position.getZ()); player.getSession().queue(msg); return this; } /** * The message that sends a hint arrow on {@code character}. * * @param character * the character to send a hint arrow on. * @return an instance of this encoder. */ public OutputMessages sendCharacterHintArrow(CharacterNode character) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(254).put(character.getType() == NodeType.NPC ? 1 : 10); msg.putShort(character.getSlot()); msg.put(0); player.getSession().queue(msg); return this; } /** * The message that sends a private message to another player. * * @param name * the name of the player you are sending the message to. * @param rights * the rights the player sending the message has. * @param message * the actual message compressed into bytes. * @param size * the size of the message being sent. * @return an instance of this encoder. */ public OutputMessages sendPrivateMessage(long name, int rights, byte[] message, int size) { MessageBuilder msg = MessageBuilder.create(); msg.newVarMessage(196); msg.putLong(name); msg.putInt(player.getPrivateMessage().getLastMessage().getAndIncrement()); msg.put(rights); msg.putBytes(message, size); msg.endVarMessage(); player.getSession().queue(msg); return this; } /** * The message that sends the players current coordinates to the client. * * @param position * the coordinates to send to the client. * @return an instance of this encoder. */ public OutputMessages sendCoordinates(Position position) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(85); msg.put(position.getY() - (player.getCurrentRegion().getRegionY() * 8), ValueType.C); msg.put(position.getX() - (player.getCurrentRegion().getRegionX() * 8), ValueType.C); player.getSession().queue(msg); return this; } /** * The message that opens a walkable interface for the underlying player. * * @param id * the identification of the interface to open. * @return an instance of this encoder. */ public OutputMessages sendWalkable(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(208); msg.putShort(id, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that spawns a ground item. * * @param item * the ground item to spawn. * @return an instance of this encoder. */ public OutputMessages sendGroundItem(ItemNode item) { sendCoordinates(item.getPosition()); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(44); msg.putShort(item.getItem().getId(), ValueType.A, ByteOrder.LITTLE); msg.putShort(item.getItem().getAmount()); msg.put(0); player.getSession().queue(msg); return this; } /** * The message that removes a ground item. * * @param item * the ground item to remove. * @return an instance of this encoder. */ public OutputMessages sendRemoveGroundItem(ItemNode item) { sendCoordinates(item.getPosition()); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(156); msg.put(0, ValueType.S); msg.putShort(item.getItem().getId()); player.getSession().queue(msg); return this; } /** * The message that sends the player context menus. * * @param slot * the slot for the option to be placed in. * @param option * the string literal option to display. * @return an instance of this encoder. */ public OutputMessages sendContextMenu(int slot, String option) { MessageBuilder msg = MessageBuilder.create(); msg.newVarMessage(104); msg.put(slot, com.asteria.net.ValueType.C); msg.put(0, com.asteria.net.ValueType.A); msg.putString(option); msg.endVarMessage(); player.getSession().queue(msg); return this; } /** * The message that attaches text to an interface. * * @param text * the text to attach to the interface. * @param id * the identification for the interface. * @return an instance of this encoder. */ public OutputMessages sendString(String text, int id) { MessageBuilder msg = MessageBuilder.create(); msg.newVarShortMessage(126); msg.putString(text); msg.putShort(id, ValueType.A); msg.endVarShortMessage(); player.getSession().queue(msg); return this; } /** * The message that opens an interface and displays another interface over * the inventory area. * * @param open * the interface to open. * @param overlay * the interface to send on the inventory area. * @return an instance of this encoder. */ public OutputMessages sendInventoryInterface(int open, int overlay) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(248); msg.putShort(open, ValueType.A); msg.putShort(overlay); player.getSession().queue(msg); return this; } /** * The message that opens an interface for underlying player. * * @param id * the identification number of the interface to open. * @return an instance of this encoder. */ public OutputMessages sendInterface(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(97); msg.putShort(id); player.getSession().queue(msg); return this; } /** * The message that sends the underlying player a message to the chatbox. * * @param message * the message to send. * @return an instance of this encoder. */ public OutputMessages sendMessage(String message) { MessageBuilder msg = MessageBuilder.create(); msg.newVarMessage(253); msg.putString(message); msg.endVarMessage(); player.getSession().queue(msg); return this; } /** * The message that sends an interface to a certain sidebar. * * @param sidebar * the sidebar to send the interface on. * @param id * the interface to send on the sidebar. * @return an instance of this encoder. */ public OutputMessages sendSidebarInterface(int sidebar, int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(71); msg.putShort(id); msg.put(sidebar, ValueType.A); player.getSession().queue(msg); return this; } /** * The message that sends the current map region. * * @return an instance of this encoder. */ public OutputMessages sendMapRegion() { player.setCurrentRegion(player.getPosition().copy()); player.setNeedsPlacement(true); player.setUpdateRegion(true); MessageBuilder msg = MessageBuilder.create(); msg.newMessage(73); msg.putShort(player.getPosition().getRegionX() + 6, com.asteria.net.ValueType.A); msg.putShort(player.getPosition().getRegionY() + 6); player.getSession().queue(msg); return this; } /** * The message that disconnects the underlying player. * * @return an instance of this encoder. */ public OutputMessages sendLogout() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(109); player.getSession().queue(msg); return this; } /** * The message that sends the slot and membership status to the client. * * @return an instance of this encoder. */ public OutputMessages sendDetails() { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(249); msg.put(1, ValueType.A); msg.putShort(player.getSlot(), ValueType.A, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } /** * The message that shows an interface in the chat box. * * @param id * the identification of interface to show. * @return an instance of this encoder. */ public OutputMessages sendChatInterface(int id) { MessageBuilder msg = MessageBuilder.create(); msg.newMessage(164); msg.putShort(id, ByteOrder.LITTLE); player.getSession().queue(msg); return this; } }