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 9dc55547..40142e71 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 @@ -49,6 +49,7 @@ 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.selector.WiredEffectFurniByType; 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; @@ -252,6 +253,7 @@ public class ItemManager { 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_slc_furni_bytype", WiredEffectFurniByType.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)); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniByType.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniByType.java new file mode 100644 index 00000000..a841dd89 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/selector/WiredEffectFurniByType.java @@ -0,0 +1,214 @@ +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 WiredEffectFurniByType extends InteractionWiredEffect { + + public static final WiredEffectType type = WiredEffectType.FURNI_BYTYPE_SELECTOR; + private static final int SOURCE_FURNI_PICKED = 0; + private static final int SOURCE_FURNI_SIGNAL = 1; + private static final int SOURCE_FURNI_TRIGGER = 2; + + private static final int MAX_PICKED_FURNI = 20; + + private int sourceType = SOURCE_FURNI_PICKED; + private boolean matchState = false; + private boolean filterExisting = false; + private boolean invert = false; + private List pickedFurniIds = new ArrayList<>(); + + public WiredEffectFurniByType(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public WiredEffectFurniByType(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) return; + + List sourceFurni = resolveSourceFurni(ctx, room); + if (sourceFurni.isEmpty()) return; + + Set matchKeys = new LinkedHashSet<>(); + for (HabboItem src : sourceFurni) { + String key = matchState + ? src.getBaseItem().getId() + ":" + src.getExtradata() + : String.valueOf(src.getBaseItem().getId()); + matchKeys.add(key); + } + + Set result = new LinkedHashSet<>(); + room.getFloorItems().forEach(item -> { + String key = matchState + ? item.getBaseItem().getId() + ":" + item.getExtradata() + : String.valueOf(item.getBaseItem().getId()); + if (matchKeys.contains(key)) { + result.add(item); + } + }); + + if (filterExisting) { + result.retainAll(ctx.targets().items()); + } + + if (invert) { + Set all = new LinkedHashSet<>(); + room.getFloorItems().forEach(all::add); + all.removeAll(result); + ctx.targets().setItems(all); + } else { + ctx.targets().setItems(result); + } + } + + private List resolveSourceFurni(WiredContext ctx, Room room) { + switch (sourceType) { + case SOURCE_FURNI_PICKED: { + return pickedFurniIds.stream() + .map(room::getHabboItem) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + case SOURCE_FURNI_SIGNAL: { + return new ArrayList<>(ctx.targets().items()); + } + case SOURCE_FURNI_TRIGGER: { + return ctx.sourceItem() + .map(Collections::singletonList) + .orElse(Collections.emptyList()); + } + 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_bytype: intParams must have at least 1 element"); + } + + this.sourceType = params[0]; + this.matchState = params.length > 1 && params[1] == 1; + this.filterExisting = params.length > 2 && params[2] == 1; + this.invert = params.length > 3 && params[3] == 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(""); + + message.appendInt(4); + message.appendInt(sourceType); + message.appendInt(matchState ? 1 : 0); + message.appendInt(filterExisting ? 1 : 0); + message.appendInt(invert ? 1 : 0); + + 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, matchState, filterExisting, invert, 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.matchState = data.matchState; + this.filterExisting = data.filterExisting; + this.invert = data.invert; + this.pickedFurniIds = data.pickedFurniIds != null ? data.pickedFurniIds : new ArrayList<>(); + this.setDelay(data.delay); + } + } + + @Override + public void onPickUp() { + this.sourceType = SOURCE_FURNI_PICKED; + this.matchState = false; + this.filterExisting = false; + this.invert = false; + 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 matchState; + boolean filterExisting; + boolean invert; + List pickedFurniIds; + int delay; + + JsonData(int sourceType, boolean matchState, boolean filterExisting, boolean invert, + List pickedFurniIds, int delay) { + this.sourceType = sourceType; + this.matchState = matchState; + this.filterExisting = filterExisting; + this.invert = invert; + this.pickedFurniIds = pickedFurniIds; + this.delay = delay; + } + } +} 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 d05538fb..c8da8f54 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 @@ -28,7 +28,8 @@ public enum WiredEffectType { BOT_CLOTHES(26), BOT_TALK_TO_AVATAR(27), FURNI_AREA_SELECTOR(28), - FURNI_NEIGHBORHOOD_SELECTOR(29); + FURNI_NEIGHBORHOOD_SELECTOR(29), + FURNI_BYTYPE_SELECTOR(30); public final int code;