diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java index ff31d6b1..9dc55547 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java @@ -47,11 +47,12 @@ import com.eu.habbo.habbohotel.items.interactions.totems.InteractionTotemLegs; import com.eu.habbo.habbohotel.items.interactions.totems.InteractionTotemPlanet; import com.eu.habbo.habbohotel.items.interactions.wired.conditions.*; import com.eu.habbo.habbohotel.items.interactions.wired.effects.*; +import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniArea; +import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniNeighborhood; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredBlob; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen; -import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniArea; import com.eu.habbo.habbohotel.items.interactions.wired.triggers.*; import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.habbohotel.users.HabboItem; @@ -249,6 +250,8 @@ public class ItemManager { this.interactionsList.add(new ItemInteraction("wf_act_alert", WiredEffectAlert.class)); this.interactionsList.add(new ItemInteraction("wf_act_give_handitem", WiredEffectGiveHandItem.class)); this.interactionsList.add(new ItemInteraction("wf_act_give_effect", WiredEffectGiveEffect.class)); + this.interactionsList.add(new ItemInteraction("wf_slc_furni_area", WiredEffectFurniArea.class)); + this.interactionsList.add(new ItemInteraction("wf_slc_furni_neighborhood", WiredEffectFurniNeighborhood.class)); this.interactionsList.add(new ItemInteraction("wf_cnd_has_furni_on", WiredConditionFurniHaveFurni.class)); this.interactionsList.add(new ItemInteraction("wf_cnd_furnis_hv_avtrs", WiredConditionFurniHaveHabbo.class)); @@ -276,8 +279,6 @@ public class ItemManager { this.interactionsList.add(new ItemInteraction("wf_cnd_date_rng_active", WiredConditionDateRangeActive.class)); this.interactionsList.add(new ItemInteraction("wf_cnd_valid_moves", WiredConditionMovementValidation.class)); - this.interactionsList.add(new ItemInteraction("wf_slc_furni_area", WiredEffectFurniArea.class)); - this.interactionsList.add(new ItemInteraction("wf_xtra_random", WiredExtraRandom.class)); this.interactionsList.add(new ItemInteraction("wf_xtra_unseen", WiredExtraUnseen.class)); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniNeighborhood.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniNeighborhood.java new file mode 100644 index 00000000..41118b42 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniNeighborhood.java @@ -0,0 +1,244 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.selector; + +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.habbohotel.items.Item; +import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect; +import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomUnit; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.habbohotel.wired.WiredEffectType; +import com.eu.habbo.habbohotel.wired.core.WiredContext; +import com.eu.habbo.habbohotel.wired.core.WiredManager; +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.incoming.wired.WiredSaveException; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +public class WiredEffectFurniNeighborhood extends InteractionWiredEffect { + + public static final WiredEffectType type = WiredEffectType.FURNI_NEIGHBORHOOD_SELECTOR; + + private static final int SOURCE_USER_TRIGGER = 0; + private static final int SOURCE_USER_SIGNAL = 1; + private static final int SOURCE_USER_CLICKED = 2; + private static final int SOURCE_FURNI_TRIGGER = 3; + private static final int SOURCE_FURNI_PICKED = 4; + private static final int SOURCE_FURNI_SIGNAL = 5; + + private static boolean isUserGroup(int src) { return src <= SOURCE_USER_CLICKED; } + private static boolean isFurniGroup(int src) { return src >= SOURCE_FURNI_TRIGGER; } + + private static final int MAX_PICKED_FURNI = 20; + private static final int MAX_TILE_OFFSETS = 64; + + private int sourceType = SOURCE_USER_TRIGGER; + private boolean filterExisting = false; + private boolean invert = false; + private List tileOffsets = new ArrayList<>(); + private List pickedFurniIds = new ArrayList<>(); + + public WiredEffectFurniNeighborhood(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public WiredEffectFurniNeighborhood(int id, int userId, Item item, String extradata, + int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } + + @Override + public void execute(WiredContext ctx) { + Room room = ctx.room(); + if (room == null || tileOffsets.isEmpty()) return; + + List sourcePositions = resolveSourcePositions(ctx, room); + if (sourcePositions.isEmpty()) return; + + Set result = new LinkedHashSet<>(); + for (int[] src : sourcePositions) { + for (int[] offset : tileOffsets) { + int tx = src[0] + offset[0]; + int ty = src[1] + offset[1]; + for (HabboItem item : room.getItemsAt(tx, ty)) { + if (item != null) result.add(item); + } + } + } + + if (filterExisting) { + result.retainAll(ctx.targets().items()); + } + + if (invert) { + Set all = new LinkedHashSet<>(); + room.getFloorItems().forEach(all::add); + all.removeAll(result); + result = all; + } + + ctx.targets().setItems(result); + } + + private List resolveSourcePositions(WiredContext ctx, Room room) { + + if (isUserGroup(sourceType)) { + List positions = ctx.targets().users().stream() + .map(u -> new int[]{ u.getX(), u.getY() }) + .collect(Collectors.toList()); + if (positions.isEmpty()) { + ctx.actor().ifPresent(a -> positions.add(new int[]{ a.getX(), a.getY() })); + } + return positions; + } + + switch (sourceType) { + case SOURCE_FURNI_TRIGGER: { + return ctx.sourceItem() + .map(i -> Collections.singletonList(new int[]{ i.getX(), i.getY() })) + .orElse(Collections.emptyList()); + } + case SOURCE_FURNI_PICKED: { + return pickedFurniIds.stream() + .map(room::getHabboItem) + .filter(Objects::nonNull) + .map(i -> new int[]{ i.getX(), i.getY() }) + .collect(Collectors.toList()); + } + case SOURCE_FURNI_SIGNAL: { + return ctx.targets().items().stream() + .map(i -> new int[]{ i.getX(), i.getY() }) + .collect(Collectors.toList()); + } + default: + return Collections.emptyList(); + } + } + + @Override + public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException { + int[] params = settings.getIntParams(); + if (params == null || params.length < 1) { + throw new WiredSaveException("wf_slc_furni_neighborhood: intParams must have at least 1 element"); + } + + this.sourceType = params[0]; + this.filterExisting = params.length > 1 && params[1] == 1; + this.invert = params.length > 2 && params[2] == 1; + + this.tileOffsets = new ArrayList<>(); + if (params.length > 3) { + int n = params[3]; + for (int i = 0; i < n && i < MAX_TILE_OFFSETS; i++) { + int xi = 4 + i * 2; + if (xi + 1 < params.length) { + tileOffsets.add(new int[]{ params[xi], params[xi + 1] }); + } + } + } + + this.pickedFurniIds = new ArrayList<>(); + if (this.sourceType == SOURCE_FURNI_PICKED && settings.getFurniIds() != null) { + for (int id : settings.getFurniIds()) { + if (pickedFurniIds.size() >= MAX_PICKED_FURNI) break; + pickedFurniIds.add(id); + } + } + + this.setDelay(settings.getDelay()); + return true; + } + + @Override + public void serializeWiredData(ServerMessage message, Room room) { + boolean pickMode = (sourceType == SOURCE_FURNI_PICKED); + + message.appendBoolean(pickMode); + message.appendInt(pickMode ? MAX_PICKED_FURNI : 0); + + if (pickMode && !pickedFurniIds.isEmpty()) { + message.appendInt(pickedFurniIds.size()); + pickedFurniIds.forEach(message::appendInt); + } else { + message.appendInt(0); + } + + message.appendInt(this.getBaseItem().getSpriteId()); + message.appendInt(this.getId()); + message.appendString(""); + + int paramCount = 4 + tileOffsets.size() * 2; + message.appendInt(paramCount); + message.appendInt(sourceType); + message.appendInt(filterExisting ? 1 : 0); + message.appendInt(invert ? 1 : 0); + message.appendInt(tileOffsets.size()); + for (int[] offset : tileOffsets) { + message.appendInt(offset[0]); + message.appendInt(offset[1]); + } + + message.appendInt(0); + message.appendInt(this.getType().code); + message.appendInt(this.getDelay()); + message.appendInt(0); + } + + @Override + public WiredEffectType getType() { return type; } + + @Override + public String getWiredData() { + return WiredManager.getGson().toJson( + new JsonData(sourceType, filterExisting, invert, tileOffsets, pickedFurniIds, getDelay())); + } + + @Override + public void loadWiredData(ResultSet set, Room room) throws SQLException { + String wiredData = set.getString("wired_data"); + if (wiredData != null && wiredData.startsWith("{")) { + JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + this.sourceType = data.sourceType; + this.filterExisting = data.filterExisting; + this.invert = data.invert; + this.tileOffsets = data.tileOffsets != null ? data.tileOffsets : new ArrayList<>(); + this.pickedFurniIds = data.pickedFurniIds != null ? data.pickedFurniIds : new ArrayList<>(); + this.setDelay(data.delay); + } + } + + @Override + public void onPickUp() { + this.sourceType = SOURCE_USER_TRIGGER; + this.filterExisting = false; + this.invert = false; + this.tileOffsets = new ArrayList<>(); + this.pickedFurniIds = new ArrayList<>(); + this.setDelay(0); + } + + @Override + public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) { return false; } + + static class JsonData { + int sourceType; + boolean filterExisting; + boolean invert; + List tileOffsets; + List pickedFurniIds; + int delay; + + JsonData(int sourceType, boolean filterExisting, boolean invert, + List tileOffsets, List pickedFurniIds, int delay) { + this.sourceType = sourceType; + this.filterExisting = filterExisting; + this.invert = invert; + this.tileOffsets = tileOffsets; + this.pickedFurniIds = pickedFurniIds; + this.delay = delay; + } + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java index a278b8cf..05093e8e 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java @@ -52,14 +52,14 @@ public class RoomChatMessageBubbles { public static final RoomChatMessageBubbles UNKNOWN_43 = new RoomChatMessageBubbles(43, "UNKNOWN_43", "", true, false); public static final RoomChatMessageBubbles UNKNOWN_44 = new RoomChatMessageBubbles(44, "UNKNOWN_44", "", true, false); public static final RoomChatMessageBubbles UNKNOWN_45 = new RoomChatMessageBubbles(45, "UNKNOWN_45", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_46 = new RoomChatMessageBubbles(46, "UNKNOWN_46", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_47 = new RoomChatMessageBubbles(47, "UNKNOWN_47", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_48 = new RoomChatMessageBubbles(48, "UNKNOWN_48", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_49 = new RoomChatMessageBubbles(49, "UNKNOWN_49", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_50 = new RoomChatMessageBubbles(50, "UNKNOWN_50", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_51 = new RoomChatMessageBubbles(51, "UNKNOWN_51", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_52 = new RoomChatMessageBubbles(52, "UNKNOWN_52", "", true, false); - public static final RoomChatMessageBubbles UNKNOWN_53 = new RoomChatMessageBubbles(53, "UNKNOWN_53", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_46 = new RoomChatMessageBubbles(45, "UNKNOWN_46", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_47 = new RoomChatMessageBubbles(45, "UNKNOWN_47", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_48 = new RoomChatMessageBubbles(45, "UNKNOWN_48", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_49 = new RoomChatMessageBubbles(45, "UNKNOWN_49", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_50 = new RoomChatMessageBubbles(45, "UNKNOWN_50", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_51 = new RoomChatMessageBubbles(45, "UNKNOWN_51", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_52 = new RoomChatMessageBubbles(45, "UNKNOWN_52", "", true, false); + public static final RoomChatMessageBubbles UNKNOWN_53 = new RoomChatMessageBubbles(45, "UNKNOWN_53", "", true, false); static { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredEffectType.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredEffectType.java index c1d506d1..d05538fb 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredEffectType.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredEffectType.java @@ -27,7 +27,8 @@ public enum WiredEffectType { BOT_FOLLOW_AVATAR(25), BOT_CLOTHES(26), BOT_TALK_TO_AVATAR(27), - FURNI_AREA_SELECTOR(28); + FURNI_AREA_SELECTOR(28), + FURNI_NEIGHBORHOOD_SELECTOR(29); public final int code;