package com.eu.habbo.habbohotel.users; import com.eu.habbo.Emulator; import com.eu.habbo.habbohotel.achievements.Achievement; import com.eu.habbo.habbohotel.achievements.AchievementManager; import com.eu.habbo.habbohotel.bots.Bot; import com.eu.habbo.habbohotel.gameclients.GameClient; import com.eu.habbo.habbohotel.items.FurnitureType; import com.eu.habbo.habbohotel.items.IEventTriggers; import com.eu.habbo.habbohotel.items.Item; import com.eu.habbo.habbohotel.items.interactions.*; import com.eu.habbo.habbohotel.items.interactions.games.InteractionGameTimer; import com.eu.habbo.habbohotel.rooms.*; import com.eu.habbo.habbohotel.wired.WiredEffectType; import com.eu.habbo.habbohotel.wired.WiredHandler; import com.eu.habbo.habbohotel.wired.WiredTriggerType; import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDanceComposer; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.UpdateUserLookComposer; import gnu.trove.set.hash.THashSet; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.math3.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public abstract class HabboItem implements Runnable, IEventTriggers { private static final Logger LOGGER = LoggerFactory.getLogger(HabboItem.class); private static Class[] TOGGLING_INTERACTIONS = new Class[]{ InteractionGameTimer.class, InteractionWired.class, InteractionWiredHighscore.class, InteractionMultiHeight.class }; private int id; private int userId; private int roomId; private Item baseItem; private String wallPosition; private short x; private short y; private double z; private int rotation; private String extradata; private int limitedStack; private int limitedSells; private boolean needsUpdate = false; private boolean needsDelete = false; private boolean isFromGift = false; public HabboItem(ResultSet set, Item baseItem) throws SQLException { this.id = set.getInt("id"); this.userId = set.getInt("user_id"); this.roomId = set.getInt("room_id"); this.baseItem = baseItem; this.wallPosition = set.getString("wall_pos"); this.x = set.getShort("x"); this.y = set.getShort("y"); this.z = set.getDouble("z"); this.rotation = set.getInt("rot"); this.extradata = set.getString("extra_data").isEmpty() ? "0" : set.getString("extra_data"); String ltdData = set.getString("limited_data"); if (!ltdData.isEmpty()) { this.limitedStack = Integer.parseInt(set.getString("limited_data").split(":")[0]); this.limitedSells = Integer.parseInt(set.getString("limited_data").split(":")[1]); } } public HabboItem(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { this.id = id; this.userId = userId; this.roomId = 0; this.baseItem = item; this.wallPosition = ""; this.x = 0; this.y = 0; this.z = 0; this.rotation = 0; this.extradata = extradata.isEmpty() ? "0" : extradata; this.limitedSells = limitedSells; this.limitedStack = limitedStack; } public static RoomTile getSquareInFront(RoomLayout roomLayout, HabboItem item) { return roomLayout.getTileInFront(roomLayout.getTile(item.getX(), item.getY()), item.getRotation()); } public void serializeFloorData(ServerMessage serverMessage) { try { serverMessage.appendInt(this.getId()); serverMessage.appendInt(this.baseItem.getSpriteId()); serverMessage.appendInt(this.x); serverMessage.appendInt(this.y); serverMessage.appendInt(this.getRotation()); serverMessage.appendString(Double.toString(this.z)); serverMessage.appendString((this.getBaseItem().getInteractionType().getType() == InteractionTrophy.class || this.getBaseItem().getInteractionType().getType() == InteractionCrackable.class || this.getBaseItem().getName().toLowerCase().equals("gnome_box")) ? "1.0" : ((this.getBaseItem().allowWalk() || this.getBaseItem().allowSit() && this.roomId != 0) ? Item.getCurrentHeight(this) + "" : "")); //serverMessage.appendString( ? "1.0" : ((this.getBaseItem().allowWalk() || this.getBaseItem().allowSit() && this.roomId != 0) ? Item.getCurrentHeight(this) : "")); } catch (Exception e) { LOGGER.error("Caught exception", e); } } public void serializeExtradata(ServerMessage serverMessage) { if (this.isLimited()) { serverMessage.appendInt(this.getLimitedSells()); serverMessage.appendInt(this.getLimitedStack()); } } public void serializeWallData(ServerMessage serverMessage) { serverMessage.appendString(this.getId() + ""); serverMessage.appendInt(this.baseItem.getSpriteId()); serverMessage.appendString(this.wallPosition); if (this instanceof InteractionPostIt) serverMessage.appendString(this.extradata.split(" ")[0]); else serverMessage.appendString(this.extradata); serverMessage.appendInt(-1); serverMessage.appendInt(this.isUsable()); serverMessage.appendInt(this.getUserId()); } public int getId() { return this.id; } public int getGiftAdjustedId() { if (this.isFromGift) return -this.id; return this.id; } public int getUserId() { return this.userId; } public void setUserId(int userId) { this.userId = userId; } public int getRoomId() { return this.roomId; } public void setRoomId(int roomId) { this.roomId = roomId; } public Item getBaseItem() { return this.baseItem; } public String getWallPosition() { return this.wallPosition; } public void setWallPosition(String wallPosition) { this.wallPosition = wallPosition; } public short getX() { return this.x; } public void setX(short x) { this.x = x; } public short getY() { return this.y; } public void setY(short y) { this.y = y; } public double getZ() { return this.z; } public void setZ(double z) { if (z > 9999 || z < -9999) return; this.z = z; } public int getRotation() { return this.rotation; } public void setRotation(int rotation) { this.rotation = (byte) (rotation % 8); } public String getExtradata() { return this.extradata; } public void setExtradata(String extradata) { this.extradata = extradata; } public boolean needsUpdate() { return this.needsUpdate; } public boolean needsDelete() { return needsDelete; } public void needsUpdate(boolean value) { this.needsUpdate = value; } public void needsDelete(boolean value) { this.needsDelete = value; } public boolean isLimited() { return this.limitedStack > 0; } public int getLimitedStack() { return this.limitedStack; } public int getLimitedSells() { return this.limitedSells; } public int getMaximumRotations() { return this.baseItem.getRotations(); } @Override public void run() { try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) { if (this.needsDelete) { this.needsUpdate = false; this.needsDelete = false; try (PreparedStatement statement = connection.prepareStatement("DELETE FROM items WHERE id = ?")) { statement.setInt(1, this.getId()); statement.execute(); } } else if (this.needsUpdate) { try (PreparedStatement statement = connection.prepareStatement("UPDATE items SET user_id = ?, room_id = ?, wall_pos = ?, x = ?, y = ?, z = ?, rot = ?, extra_data = ?, limited_data = ? WHERE id = ?")) { statement.setInt(1, this.userId); statement.setInt(2, this.roomId); statement.setString(3, this.wallPosition); statement.setInt(4, this.x); statement.setInt(5, this.y); statement.setDouble(6, Math.max(-9999, Math.min(9999, Math.round(this.z * Math.pow(10, 6)) / Math.pow(10, 6)))); statement.setInt(7, this.rotation); statement.setString(8, this instanceof InteractionGuildGate ? "" : this.getDatabaseExtraData()); statement.setString(9, this.limitedStack + ":" + this.limitedSells); statement.setInt(10, this.id); statement.execute(); } catch (SQLException e) { LOGGER.error("Caught SQL exception", e); LOGGER.error("SQLException trying to save HabboItem: " + this.toString()); } this.needsUpdate = false; } } catch (SQLException e) { LOGGER.error("Caught SQL exception", e); } } public abstract boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects); public abstract boolean isWalkable(); @Override public void onClick(GameClient client, Room room, Object[] objects) throws Exception { if (client != null && this.getBaseItem().getType() == FurnitureType.FLOOR) { if (objects != null && objects.length >= 2) { if (objects[1] instanceof WiredEffectType) { return; } } if ((this.getBaseItem().getStateCount() > 1 && !(this instanceof InteractionDice)) || Arrays.asList(HabboItem.TOGGLING_INTERACTIONS).contains(this.getClass()) || (objects != null && objects.length == 1 && objects[0].equals("TOGGLE_OVERRIDE"))) { WiredHandler.handle(WiredTriggerType.STATE_CHANGED, client.getHabbo().getRoomUnit(), room, new Object[]{this}); } } } @Override public void onWalkOn(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { /*if (objects != null && objects.length >= 1 && objects[0] instanceof InteractionWired) return;*/ WiredHandler.handle(WiredTriggerType.WALKS_ON_FURNI, roomUnit, room, new Object[]{this}); if ((this.getBaseItem().allowSit() || this.getBaseItem().allowLay()) && !roomUnit.getDanceType().equals(DanceType.NONE)) { roomUnit.setDanceType(DanceType.NONE); room.sendComposer(new RoomUserDanceComposer(roomUnit).compose()); } if (!this.getBaseItem().getClothingOnWalk().isEmpty() && roomUnit.getPreviousLocation() != roomUnit.getGoal() && roomUnit.getGoal() == room.getLayout().getTile(this.x, this.y)) { Habbo habbo = room.getHabbo(roomUnit); if (habbo != null && habbo.getClient() != null) { String[] clothingKeys = Arrays.stream(this.getBaseItem().getClothingOnWalk().split("\\.")).map(k -> k.split("-")[0]).toArray(String[]::new); habbo.getHabboInfo().setLook(String.join(".", Arrays.stream(habbo.getHabboInfo().getLook().split("\\.")).filter(k -> !ArrayUtils.contains(clothingKeys, k.split("-")[0])).toArray(String[]::new)) + "." + this.getBaseItem().getClothingOnWalk()); habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo)); if (habbo.getHabboInfo().getCurrentRoom() != null) { habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(habbo).compose()); } } } } @Override public void onWalkOff(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { if(objects != null && objects.length > 0) { WiredHandler.handle(WiredTriggerType.WALKS_OFF_FURNI, roomUnit, room, new Object[]{this}); } } public abstract void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception; public void onPlace(Room room) { //TODO: IMPORTANT: MAKE THIS GENERIC. (HOLES, ICE SKATE PATCHES, BLACK HOLE, BUNNY RUN FIELD, FOOTBALL FIELD) Achievement roomDecoAchievement = Emulator.getGameEnvironment().getAchievementManager().getAchievement("RoomDecoFurniCount"); Habbo owner = room.getHabbo(this.getUserId()); int furniCollecterProgress; if (owner == null) { furniCollecterProgress = AchievementManager.getAchievementProgressForHabbo(this.getUserId(), roomDecoAchievement); } else { furniCollecterProgress = owner.getHabboStats().getAchievementProgress(roomDecoAchievement); } int difference = room.getUserFurniCount(this.getUserId()) - furniCollecterProgress; if (difference > 0) { if (owner != null) { AchievementManager.progressAchievement(owner, roomDecoAchievement, difference); } else { AchievementManager.progressAchievement(this.getUserId(), roomDecoAchievement, difference); } } Achievement roomDecoUniqueAchievement = Emulator.getGameEnvironment().getAchievementManager().getAchievement("RoomDecoFurniTypeCount"); int uniqueFurniCollecterProgress; if (owner == null) { uniqueFurniCollecterProgress = AchievementManager.getAchievementProgressForHabbo(this.getUserId(), roomDecoUniqueAchievement); } else { uniqueFurniCollecterProgress = owner.getHabboStats().getAchievementProgress(roomDecoUniqueAchievement); } int uniqueDifference = room.getUserUniqueFurniCount(this.getUserId()) - uniqueFurniCollecterProgress; if (uniqueDifference > 0) { if (owner != null) { AchievementManager.progressAchievement(owner, roomDecoUniqueAchievement, uniqueDifference); } else { AchievementManager.progressAchievement(this.getUserId(), roomDecoUniqueAchievement, uniqueDifference); } } } public void onPickUp(Room room) { if (this.getBaseItem().getEffectF() > 0 || this.getBaseItem().getEffectM() > 0) { HabboItem topItem2 = room.getTopItemAt(this.getX(), this.getY(), this); int nextEffectM = 0; int nextEffectF = 0; if(topItem2 != null) { nextEffectM = topItem2.getBaseItem().getEffectM(); nextEffectF = topItem2.getBaseItem().getEffectF(); } for (Habbo habbo : room.getHabbosOnItem(this)) { if (this.getBaseItem().getEffectM() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.M) && habbo.getRoomUnit().getEffectId() == this.getBaseItem().getEffectM()) { room.giveEffect(habbo, nextEffectM, -1); } if (this.getBaseItem().getEffectF() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.F) && habbo.getRoomUnit().getEffectId() == this.getBaseItem().getEffectF()) { room.giveEffect(habbo, nextEffectF, -1); } } for (Bot bot : room.getBotsAt(room.getLayout().getTile(this.getX(), this.getY()))) { if (this.getBaseItem().getEffectM() > 0 && bot.getGender().equals(HabboGender.M) && bot.getRoomUnit().getEffectId() == this.getBaseItem().getEffectM()) { room.giveEffect(bot.getRoomUnit(), nextEffectM, -1); } if (this.getBaseItem().getEffectF() > 0 && bot.getGender().equals(HabboGender.F) && bot.getRoomUnit().getEffectId() == this.getBaseItem().getEffectF()) { room.giveEffect(bot.getRoomUnit(), nextEffectF, -1); } } } } public void onMove(Room room, RoomTile oldLocation, RoomTile newLocation) { if (this.getBaseItem().getEffectF() > 0 || this.getBaseItem().getEffectM() > 0) { HabboItem topItem2 = room.getTopItemAt(oldLocation.x, oldLocation.y, this); int nextEffectM = 0; int nextEffectF = 0; if(topItem2 != null) { nextEffectM = topItem2.getBaseItem().getEffectM(); nextEffectF = topItem2.getBaseItem().getEffectF(); } List oldHabbos = new ArrayList<>(); List newHabbos = new ArrayList<>(); List oldBots = new ArrayList<>(); List newBots = new ArrayList<>(); for (RoomTile tile : room.getLayout().getTilesAt(oldLocation, this.getBaseItem().getWidth(), this.getBaseItem().getLength(), this.getRotation())) { oldHabbos.addAll(room.getHabbosAt(tile)); oldBots.addAll(room.getBotsAt(tile)); } for (RoomTile tile : room.getLayout().getTilesAt(oldLocation, this.getBaseItem().getWidth(), this.getBaseItem().getLength(), this.getRotation())) { newHabbos.addAll(room.getHabbosAt(tile)); newBots.addAll(room.getBotsAt(tile)); } oldHabbos.removeAll(newHabbos); oldBots.removeAll(newBots); for (Habbo habbo : oldHabbos) { if (this.getBaseItem().getEffectM() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.M) && habbo.getRoomUnit().getEffectId() == this.getBaseItem().getEffectM()) { room.giveEffect(habbo, nextEffectM, -1); } if (this.getBaseItem().getEffectF() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.F) && habbo.getRoomUnit().getEffectId() == this.getBaseItem().getEffectF()) { room.giveEffect(habbo, nextEffectF, -1); } } for (Habbo habbo : newHabbos) { if (this.getBaseItem().getEffectM() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.M) && habbo.getRoomUnit().getEffectId() != this.getBaseItem().getEffectM()) { room.giveEffect(habbo, this.getBaseItem().getEffectM(), -1); } if (this.getBaseItem().getEffectF() > 0 && habbo.getHabboInfo().getGender().equals(HabboGender.F) && habbo.getRoomUnit().getEffectId() != this.getBaseItem().getEffectF()) { room.giveEffect(habbo, this.getBaseItem().getEffectF(), -1); } } for (Bot bot : oldBots) { if (this.getBaseItem().getEffectM() > 0 && bot.getGender().equals(HabboGender.M) && bot.getRoomUnit().getEffectId() == this.getBaseItem().getEffectM()) { room.giveEffect(bot.getRoomUnit(), nextEffectM, -1); } if (this.getBaseItem().getEffectF() > 0 && bot.getGender().equals(HabboGender.F) && bot.getRoomUnit().getEffectId() == this.getBaseItem().getEffectF()) { room.giveEffect(bot.getRoomUnit(), nextEffectF, -1); } } for (Bot bot : newBots) { if (this.getBaseItem().getEffectM() > 0 && bot.getGender().equals(HabboGender.M) && bot.getRoomUnit().getEffectId() != this.getBaseItem().getEffectM()) { room.giveEffect(bot.getRoomUnit(), this.getBaseItem().getEffectM(), -1); } if (this.getBaseItem().getEffectF() > 0 && bot.getGender().equals(HabboGender.F) && bot.getRoomUnit().getEffectId() != this.getBaseItem().getEffectF()) { room.giveEffect(bot.getRoomUnit(), this.getBaseItem().getEffectF(), -1); } } } } public String getDatabaseExtraData() { return this.getExtradata(); } @Override public String toString() { return "ID: " + this.id + ", BaseID: " + this.getBaseItem().getId() + ", X: " + this.x + ", Y: " + this.y + ", Z: " + this.z + ", Extradata: " + this.extradata; } public boolean allowWiredResetState() { return false; } public boolean isUsable() { return this.baseItem.getStateCount() > 1; } public boolean canStackAt(Room room, List>> itemsAtLocation) { return true; } public boolean isFromGift() { return isFromGift; } public void setFromGift(boolean fromGift) { isFromGift = fromGift; } public boolean invalidatesToRoomKick() { return false; } public List getOccupyingTiles(RoomLayout layout) { List tiles = new ArrayList<>(); Rectangle rect = RoomLayout.getRectangle(this.getX(), this.getY(), this.getBaseItem().getWidth(), this.getBaseItem().getLength(), this.getRotation()); for (int i = rect.x; i < rect.x + rect.getWidth(); i++) { for (int j = rect.y; j < rect.y + rect.getHeight(); j++) { tiles.add(layout.getTile((short) i, (short) j)); } } return tiles; } public RoomTile getOverrideGoalTile(RoomUnit unit, Room room, RoomTile tile) { return tile; } public RoomTileState getOverrideTileState(RoomTile tile, Room room) { return null; } public boolean canOverrideTile(RoomUnit unit, Room room, RoomTile tile) { return false; } public Rectangle getRectangle() { return RoomLayout.getRectangle( this.getX(), this.getY(), this.getBaseItem().getWidth(), this.getBaseItem().getLength(), this.getRotation()); } public Rectangle getRectangle(int marginX, int marginY) { return RoomLayout.getRectangle( this.getX() - marginX, this.getY() - marginY, this.getBaseItem().getWidth() + (marginX * 2), this.getBaseItem().getLength() + (marginY * 2), this.getRotation()); } }