/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.client.gui.controller.game; import de.lessvoid.nifty.Nifty; import de.lessvoid.nifty.NiftyEventSubscriber; import de.lessvoid.nifty.builder.ControlBuilder; import de.lessvoid.nifty.elements.Element; import de.lessvoid.nifty.screen.Screen; import de.lessvoid.nifty.screen.ScreenController; import de.lessvoid.nifty.tools.SizeValue; import illarion.client.graphics.FontLoader; import illarion.client.gui.*; import illarion.client.gui.controller.game.NumberSelectPopupHandler.Callback; import illarion.client.gui.events.TooltipsRemovedEvent; import illarion.client.gui.util.NiftyCraftingCategory; import illarion.client.gui.util.NiftyCraftingItem; import illarion.client.gui.util.NiftyMerchantItem; import illarion.client.gui.util.NiftySelectItem; import illarion.client.net.client.*; import illarion.client.util.Lang; import illarion.client.world.Char; import illarion.client.world.World; import illarion.client.world.items.CraftingItem; import illarion.client.world.items.MerchantItem; import illarion.client.world.items.MerchantItem.MerchantItemType; import illarion.client.world.items.MerchantList; import illarion.client.world.items.SelectionItem; import illarion.common.types.CharacterId; import illarion.common.types.ItemCount; import illarion.common.types.ItemId; import illarion.common.types.Rectangle; import org.bushe.swing.event.annotation.AnnotationProcessor; import org.bushe.swing.event.annotation.EventSubscriber; import org.illarion.engine.GameContainer; import org.illarion.engine.graphic.Font; import org.illarion.engine.input.Button; import org.illarion.engine.input.Input; import org.illarion.engine.input.Key; import org.illarion.nifty.controls.*; import org.illarion.nifty.controls.DialogInput.DialogButton; import org.illarion.nifty.controls.dialog.input.builder.DialogInputBuilder; import org.illarion.nifty.controls.dialog.message.builder.DialogMessageBuilder; import org.illarion.nifty.controls.dialog.select.builder.DialogSelectBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This class is the dialog handler that takes care for receiving events to show dialogs. It opens and maintains those * dialogs and notifies the server in case a dialog is closed. * * @author Martin Karing <nitram@illarion.org> */ public final class DialogHandler implements DialogGui, DialogCraftingGui, DialogMerchantGui, DialogMessageGui, DialogInputGui, DialogSelectionGui, ScreenController, UpdatableHandler { private static class BuildWrapper { @Nonnull private final ControlBuilder builder; @Nonnull private final Element parent; @Nullable private final PostBuildTask task; BuildWrapper(@Nonnull ControlBuilder builder, @Nonnull Element parent, @Nullable PostBuildTask task) { this.builder = builder; this.parent = parent; this.task = task; } public void executeTask(@Nonnull Element createdElement) { if (task != null) { task.run(createdElement); } } @Nonnull public ControlBuilder getBuilder() { return builder; } @Nonnull public Element getParent() { return parent; } } private static class DialogCloseData { @Nonnull public final Set<DialogType> types; public final int dialogId; public DialogCloseData(int id, @Nonnull Collection<DialogType> types) { this.types = EnumSet.copyOf(types); dialogId = id; } } private interface PostBuildTask { void run(@Nonnull Element createdElement); } @Nonnull private static final Logger log = LoggerFactory.getLogger(DialogHandler.class); @Nonnull private static final Pattern dialogNamePattern = Pattern.compile("([a-z]+)Dialog([0-9]+)"); /** * The input control that is used in this dialog handler. */ private final Input input; @Nullable private DialogMerchant merchantDialog; @Nullable private DialogCrafting craftingDialog; private boolean openCraftDialog; private boolean craftingInProgress; @Nonnull private final Queue<BuildWrapper> builders; @Nonnull private final Queue<DialogCloseData> closers; private Nifty nifty; private Screen screen; private final NumberSelectPopupHandler numberSelect; private final TooltipHandler tooltipHandler; private int lastCraftingTooltip = -2; @Nullable private MerchantListEntry lastMerchantTooltipItem; public DialogHandler( Input input, NumberSelectPopupHandler numberSelectPopupHandler, TooltipHandler tooltipHandler) { this.input = input; this.tooltipHandler = tooltipHandler; builders = new ConcurrentLinkedQueue<>(); closers = new ConcurrentLinkedQueue<>(); numberSelect = numberSelectPopupHandler; } private void addCraftingItemsToDialog(@Nonnull Iterable<String> groups, @Nonnull Iterable<CraftingItem> items, @Nonnull DialogCrafting dialog) { if (nifty == null) { throw new IllegalStateException("Dialog handler is not bound yet."); } List<NiftyCraftingCategory> categories = new ArrayList<>(); for (@Nonnull String group : groups) { categories.add(new NiftyCraftingCategory(group)); } NiftyCraftingCategory unknownCat = null; for (CraftingItem item : items) { int groupId = item.getGroup(); if ((groupId < 0) || (groupId >= categories.size())) { if (unknownCat == null) { unknownCat = new NiftyCraftingCategory("not assigned"); } unknownCat.addChild(new NiftyCraftingItem(nifty, item)); log.warn("Crafting item with illegal group received: {}", Integer.toString(groupId)); } else { NiftyCraftingCategory category = categories.get(item.getGroup()); assert category != null; category.addChild(new NiftyCraftingItem(nifty, item)); } } dialog.addCraftingItems(categories); if (unknownCat != null) { dialog.addCraftingItems(unknownCat); } } @Override public void showSelectionDialog(int dialogId, @Nonnull String title, @Nonnull String content, @Nonnull Collection<SelectionItem> items) { World.getUpdateTaskManager().addTask((container, delta) -> showSelectionDialogImpl(dialogId, title, content, items)); } private void showSelectionDialogImpl(int dialogId, @Nonnull String title, @Nonnull String content, @Nonnull Collection<SelectionItem> items) { if (screen == null) { throw new IllegalStateException("UI is not ready yet."); } Element parentArea = screen.findElementById("windows"); if (parentArea == null) { throw new IllegalStateException("UI is corrupted. Windows panel not found."); } DialogSelectBuilder builder = new DialogSelectBuilder("selectDialog" + dialogId, title); builder.dialogId(dialogId); builder.message(content); int selectedWidth = 0; boolean useImages = false; Font textFont = FontLoader.getInstance().getFont(FontLoader.TEXT_FONT); for (@Nonnull SelectionItem item : items) { useImages = useImages || ItemId.isValidItem(item.getId()); selectedWidth = Math.max(selectedWidth, textFont.getWidth(item.getName())); } if (useImages) { selectedWidth += 79; // width of the image container area } selectedWidth += 2; // padding of entry selectedWidth += 26; // padding of list box and window if (items.size() > 6) { selectedWidth += 16; // space for the scroll bar } selectedWidth += 10; // padding to make it look good (some space on the right side of the text entries) selectedWidth += 20; // magical additional width of unknown origin (determined by testing) selectedWidth = Math.max(selectedWidth, 270); // width required to display the buttons properly builder.width(SizeValue.px(selectedWidth)); builder.itemCount(Math.min(6, items.size())); builders.add(new BuildWrapper(builder, parentArea, createdElement -> { DialogSelect dialog = createdElement.getNiftyControl(DialogSelect.class); if (dialog == null) { log.warn("Newly created dialog was NULL"); } else { if (nifty == null) { throw new IllegalStateException("UI is not ready yet."); } for (@Nonnull SelectionItem item : items) { dialog.addItem(new NiftySelectItem(nifty, item)); } } })); } @EventSubscriber public void handleTooltipRemovedEvent(TooltipsRemovedEvent event) { lastCraftingTooltip = -2; lastMerchantTooltipItem = null; if (input.isAnyButtonDown(Button.Left, Button.Right)) { return; } } @NiftyEventSubscriber(id = "craftingDialog") public void handleCraftingCloseDialogEvent(String topic, @Nonnull DialogCraftingCloseEvent event) { closeCraftingDialog(event.getDialogId()); } private void closeCraftingDialog(int id) { if (!openCraftDialog) { return; } World.getNet().sendCommand(new CloseDialogCraftingCmd(id)); World.getGameGui().getDialogGui().closeDialog(id, EnumSet.of(DialogType.Crafting)); openCraftDialog = false; } @NiftyEventSubscriber(id = "craftingDialog") public void handleCraftingCraftItemEvent(String topic, @Nonnull DialogCraftingCraftEvent event) { World.getNet() .sendCommand(new CraftItemCmd(event.getDialogId(), event.getItem().getItemIndex(), event.getCount())); } @NiftyEventSubscriber(id = "craftingDialog") public void handleCraftingIngredientLookAtEvent( String topic, @Nonnull DialogCraftingLookAtIngredientItemEvent event) { if (lastCraftingTooltip == event.getIngredientIndex()) { return; } if (input.isAnyButtonDown(Button.Left, Button.Right)) { return; } World.getNet().sendCommand(new LookAtCraftIngredientCmd(event.getDialogId(), event.getItem().getItemIndex(), event.getIngredientIndex())); lastCraftingTooltip = event.getIngredientIndex(); } @NiftyEventSubscriber(id = "craftingDialog") public void handleCraftingItemLookAtEvent(String topic, @Nonnull DialogCraftingLookAtItemEvent event) { if (lastCraftingTooltip == -1) { return; } if (input.isAnyButtonDown(Button.Left, Button.Right)) { return; } World.getNet().sendCommand(new LookAtCraftItemCmd(event.getDialogId(), event.getItem().getItemIndex())); lastCraftingTooltip = -1; } @NiftyEventSubscriber(id = "merchantDialog") public void handleMerchantLookAtEvent(String topic, @Nonnull DialogMerchantLookAtEvent event) { if (input.isAnyButtonDown(Button.Left, Button.Right)) { return; } if (Objects.equals(lastMerchantTooltipItem, event.getItem())) { return; } byte listId = -1; switch (event.getItem().getEntryType()) { case Selling: listId = LookAtMerchantItemCmd.LIST_ID_SELL; break; case BuyPrimary: listId = LookAtMerchantItemCmd.LIST_ID_BUY_PRIMARY; break; case BuySecondary: listId = LookAtMerchantItemCmd.LIST_ID_BUY_SECONDARY; break; } int dialogId = event.getDialogId(); int itemIndex = event.getItem().getIndex(); lastMerchantTooltipItem = event.getItem(); LookAtMerchantItemCmd cmd = new LookAtMerchantItemCmd(dialogId, listId, itemIndex); World.getNet().sendCommand(cmd); } @Override public void bind(@Nonnull Nifty nifty, @Nonnull Screen screen) { this.nifty = nifty; this.screen = screen; merchantDialog = this.screen.findNiftyControl("merchantDialog", DialogMerchant.class); craftingDialog = this.screen.findNiftyControl("craftingDialog", DialogCrafting.class); } @Override public void onEndScreen() { AnnotationProcessor.unprocess(this); nifty.unsubscribeAnnotations(this); closeDialogImpl(ALL_DIALOGS, EnumSet.allOf(DialogType.class)); } @Override public void onStartScreen() { AnnotationProcessor.process(this); nifty.subscribeAnnotations(this); } @Override public void showMerchantListTooltip(int dialogId, int list, int itemIndex, @Nonnull Tooltip tooltip) { if ((merchantDialog == null) || (merchantDialog.getDialogId() != dialogId)) { return; } MerchantList merchantList = World.getPlayer().getMerchantList(); if (merchantList == null) { log.warn("Received tooltip for merchant dialog {} but there is no merchant list.", dialogId); return; } MerchantItemType expectedItemType; switch (list) { case 0: expectedItemType = MerchantItemType.SellingItem; break; case 1: expectedItemType = MerchantItemType.BuyingPrimaryItem; break; case 2: expectedItemType = MerchantItemType.BuyingSecondaryItem; break; default: log.warn("Received merchant item look-at for unexpected list: {}", list); return; } MerchantItem selectedItem = merchantList.getItem(expectedItemType, itemIndex); if (selectedItem == null) { log.warn("Failed to located item index {} in merchant list {} ({}) for dialog {}.", itemIndex, expectedItemType, list, dialogId); return; } Rectangle renderArea = merchantDialog.getRenderAreaForEntry(new NiftyMerchantItem(nifty, selectedItem)); if (!renderArea.isEmpty()) { tooltipHandler.showToolTip(renderArea, tooltip); } } @Override public void showMerchantDialog(int dialogId, @Nonnull String title, @Nonnull Collection<MerchantItem> items) { World.getUpdateTaskManager().addTask((container, delta) -> showMerchantDialogImpl(dialogId, title, items)); } private void showMerchantDialogImpl(int dialogId, @Nonnull String title, @Nonnull Iterable<MerchantItem> items) { if ((merchantDialog == null) || (nifty == null)) { log.error("Can't show the merchant dialog. Binding is now done."); return; } merchantDialog.clearItems(); merchantDialog.setDialogId(dialogId); merchantDialog.setTitle(title); Collection<MerchantListEntry> sellingList = new ArrayList<>(); Collection<MerchantListEntry> buyingList = new ArrayList<>(); for (MerchantItem item : items) { NiftyMerchantItem niftyItem = new NiftyMerchantItem(nifty, item); switch (niftyItem.getType()) { case SellingItem: sellingList.add(niftyItem); break; case BuyingPrimaryItem: case BuyingSecondaryItem: buyingList.add(niftyItem); break; } } merchantDialog.addAllSellingItems(sellingList); merchantDialog.addAllBuyingItems(buyingList); Element element = merchantDialog.getElement(); if (element != null) { if (element.isVisible()) { merchantDialog.moveToFront(); } else { element.show(merchantDialog::moveToFront); } } } @Override public void showCraftIngredientTooltip( int dialogId, int index, int ingredientIndex, @Nonnull Tooltip tooltip) { if ((craftingDialog == null) || (craftingDialog.getDialogId() != dialogId)) { return; } CraftingItemEntry selectedEntry = craftingDialog.getSelectedCraftingItem(); if ((selectedEntry != null) && (selectedEntry.getItemIndex() == index)) { Element targetElement = craftingDialog.getIngredientItemDisplay(ingredientIndex); Rectangle elementRectangle = new Rectangle(); elementRectangle.set(targetElement.getX(), targetElement.getY(), targetElement.getWidth(), targetElement.getHeight()); tooltipHandler.showToolTip(elementRectangle, tooltip); } } @Override public void showCraftItemTooltip(int dialogId, int index, @Nonnull Tooltip tooltip) { if ((craftingDialog == null) || (craftingDialog.getDialogId() != dialogId)) { return; } CraftingItemEntry selectedEntry = craftingDialog.getSelectedCraftingItem(); if ((selectedEntry != null) && (selectedEntry.getItemIndex() == index)) { Element targetElement = craftingDialog.getCraftingItemDisplay(); Rectangle elementRectangle = new Rectangle(); elementRectangle.set(targetElement.getX(), targetElement.getY(), targetElement.getWidth(), targetElement.getHeight()); tooltipHandler.showToolTip(elementRectangle, tooltip); } } private void showCraftingDialogImpl(int dialogId, @Nonnull String title, @Nonnull Iterable<String> groups, @Nonnull Iterable<CraftingItem> items) { if (craftingDialog == null) { throw new IllegalStateException("Instance of crafting dialog not found. Binding not done?"); } if ((dialogId == craftingDialog.getDialogId()) && openCraftDialog) { CraftingItemEntry selectedItem = craftingDialog.getSelectedCraftingItem(); int selectedIndex = (selectedItem != null) ? selectedItem.getItemIndex() : 0; craftingDialog.clearItemList(); addCraftingItemsToDialog(groups, items, craftingDialog); if (selectedItem != null) { craftingDialog.selectItemByItemIndex(selectedIndex); } } else { craftingDialog.setDialogId(dialogId); craftingDialog.setTitle(title); craftingDialog.clearItemList(); addCraftingItemsToDialog(groups, items, craftingDialog); craftingDialog.setProgress(0.f); craftingDialog.selectItemByItemIndex(0); craftingDialog.setAmount(1); Element craftingDialogElement = craftingDialog.getElement(); if (craftingDialogElement != null) { craftingDialogElement.show(() -> { assert craftingDialog != null; craftingDialog.moveToFront(); craftingDialog.selectItemByItemIndex(0); }); } openCraftDialog = true; } } @Override public void showCraftingDialog(int dialogId, @Nonnull String title, @Nonnull Collection<String> groups, @Nonnull Collection<CraftingItem> items) { World.getUpdateTaskManager().addTask((container, delta) -> showCraftingDialogImpl(dialogId, title, groups, items)); } @Override public void startProductionIndicator(int dialogId, int remainingItemCount, double requiredTime) { World.getUpdateTaskManager().addTask((container, delta) -> { if ((craftingDialog != null) && openCraftDialog && (craftingDialog.getDialogId() == dialogId)) { craftingDialog.setAmount(remainingItemCount); craftingDialog.startProgress(requiredTime); craftingInProgress = true; } }); } @Override public void finishProduction(int dialogId) { World.getUpdateTaskManager().addTask((container, delta) -> { if ((craftingDialog != null) && openCraftDialog && (craftingDialog.getDialogId() == dialogId)) { craftingDialog.setAmount(craftingDialog.getAmount() - 1); craftingDialog.setProgress(0.f); craftingInProgress = false; } }); } @Override public void abortProduction(int dialogId) { World.getUpdateTaskManager().addTask((container, delta) -> { if ((craftingDialog != null) && openCraftDialog && (craftingDialog.getDialogId() == dialogId)) { craftingDialog.setProgress(0.f); craftingInProgress = false; } }); } @Override public boolean isCraftingInProgress() { return craftingInProgress; } @Override public void showInputDialog( int dialogId, @Nonnull String title, @Nonnull String message, int maxLength, boolean multiLine) { Element parentArea = screen.findElementById("windows"); DialogInputBuilder builder = new DialogInputBuilder("inputDialog" + Integer.toString(dialogId), title); builder.description(message); builder.buttonLeft("OK"); builder.buttonRight("Cancel"); builder.dialogId(dialogId); builder.maxLength(maxLength); if (multiLine) { builder.style("illarion-dialog-input-multi"); } else { builder.style("illarion-dialog-input-single"); } builders.add(new BuildWrapper(builder, parentArea, createdElement -> { DialogInput control = createdElement.getNiftyControl(DialogInput.class); if (control != null) { control.setFocus(); } })); } @Override public void showNamingDialog(@Nonnull Char chara) { Element parentArea = screen.findElementById("windows"); CharacterId charId = chara.getCharId(); if ((charId == null) || !charId.isHuman() || World.getPlayer().isPlayer(charId)) { return; } String currentCustomName = chara.getCustomName(); String dialogName = "namingDialog" + Long.toString(charId.getValue()); if (parentArea.findElementById(dialogName) != null) { return; } DialogInputBuilder builder = new DialogInputBuilder(dialogName, Lang.getMsg("gui.dialog.naming.title")); builder.description(String.format(Lang.getMsg("gui.dialog.naming.description"), chara.getName())); builder.buttonLeft(Lang.getMsg("gui.dialog.naming.ok")); builder.buttonRight(Lang.getMsg("gui.dialog.naming.cancel")); builder.dialogId(charId.getAsInteger()); builder.maxLength(255); builder.initalText((currentCustomName == null) ? "" : currentCustomName); builder.style("illarion-dialog-input-single"); builders.add(new BuildWrapper(builder, parentArea, createdElement -> { DialogInput control = createdElement.getNiftyControl(DialogInput.class); if (control != null) { control.setFocus(); } })); } @Override public void showMessageDialog(int dialogId, @Nonnull String title, @Nonnull String message) { Element parentArea = screen.findElementById("windows"); DialogMessageBuilder builder = new DialogMessageBuilder("msgDialog" + Integer.toString(dialogId), title); builder.text(message); builder.button("OK"); builder.dialogId(dialogId); builders.add(new BuildWrapper(builder, parentArea, null)); } @Override public void update(@Nonnull GameContainer container, int delta) { while (true) { BuildWrapper wrapper = builders.poll(); if (wrapper == null) { break; } Element element = wrapper.getBuilder().build(nifty, screen, wrapper.getParent()); wrapper.executeTask(element); element.layoutElements(); element.setConstraintX(SizeValue.px((wrapper.getParent().getWidth() - element.getWidth()) / 2)); element.setConstraintY(SizeValue.px((wrapper.getParent().getHeight() - element.getHeight()) / 2)); wrapper.getParent().layoutElements(); } while (true) { DialogCloseData closeEvent = closers.poll(); if (closeEvent == null) { break; } closeDialogImpl(closeEvent.dialogId, closeEvent.types); } } @Nullable @Override public DialogType getDialogType(int dialogId) { return getDialogType(dialogId, EnumSet.allOf(DialogType.class)); } @Nullable @Override public DialogType getDialogType(int dialogId, @Nonnull DialogType firstType, @Nonnull DialogType... moreTypes) { return getDialogType(dialogId, EnumSet.of(firstType, moreTypes)); } @Override public void closeDialog(int dialogId, @Nonnull Collection<DialogType> dialogTypes) { closers.add(new DialogCloseData(dialogId, dialogTypes)); } @Nullable public DialogType getDialogType(int dialogId, @Nonnull Collection<DialogType> types) { if (types.contains(DialogType.Merchant)) { if (merchantDialog != null) { if (dialogId == merchantDialog.getDialogId()) { return DialogType.Merchant; } } } if (types.contains(DialogType.Crafting)) { if (craftingDialog != null) { if (dialogId == craftingDialog.getDialogId()) { return DialogType.Crafting; } } } Element parentArea = screen.findElementById("windows"); if (parentArea == null) { return null; } for (Element child : parentArea.getChildren()) { String childId = child.getId(); if (childId == null) { continue; } Matcher matcher = dialogNamePattern.matcher(childId); if (!matcher.find()) { continue; } try { String type = matcher.group(1); int id = Integer.parseInt(matcher.group(2)); if (id == dialogId) { if ("msg".equals(type) && types.contains(DialogType.Message)) { return DialogType.Message; } if ("input".equals(type) && types.contains(DialogType.Input)) { return DialogType.Input; } if ("select".equals(type) && types.contains(DialogType.Selection)) { return DialogType.Selection; } } } catch (@Nonnull NumberFormatException ignored) { // nothing } } return null; } private void closeDialogImpl(int dialogId, @Nonnull Collection<DialogType> dialogTypes) { if (screen == null) { return; } Element parentArea = screen.findElementById("windows"); if (parentArea == null) { return; } if (dialogTypes.contains(DialogType.Merchant)) { if ((merchantDialog != null) && merchantDialog.getElement().isVisible()) { if ((dialogId == ALL_DIALOGS) || (dialogId == merchantDialog.getDialogId())) { merchantDialog.closeWindow(); } } } if (dialogTypes.contains(DialogType.Crafting)) { if ((craftingDialog != null) && craftingDialog.getElement().isVisible()) { if ((dialogId == ALL_DIALOGS) || (dialogId == craftingDialog.getDialogId())) { craftingDialog.closeWindow(); } } } for (Element child : parentArea.getChildren()) { String childId = child.getId(); if (childId == null) { continue; } Matcher matcher = dialogNamePattern.matcher(childId); if (!matcher.find()) { continue; } try { String type = matcher.group(1); int id = Integer.parseInt(matcher.group(2)); if ((dialogId == ALL_DIALOGS) || (id == dialogId)) { if ("msg".equals(type) && dialogTypes.contains(DialogType.Message)) { child.hide(child::markForRemoval); } if ("input".equals(type) && dialogTypes.contains(DialogType.Input)) { child.hide(child::markForRemoval); } if ("select".equals(type) && dialogTypes.contains(DialogType.Selection)) { child.hide(child::markForRemoval); } } } catch (@Nonnull NumberFormatException ignored) { // nothing } } } @NiftyEventSubscriber(id = "merchantDialog") public void handleMerchantBuyEvent(String topic, @Nonnull DialogMerchantBuyEvent event) { MerchantList list = World.getPlayer().getMerchantList(); if (list == null) { log.error("Buying event received, but there is not merchant list."); return; } int index = event.getItem().getIndex(); if (ItemCount.isGreaterOne(list.getItem(index).getBundleSize())) { list.buyItem(index); } else { if (input.isAnyKeyDown(Key.LeftShift, Key.RightShift)) { numberSelect.requestNewPopup(1, 250, new Callback() { @Override public void popupCanceled() { // nothing } @Override public void popupConfirmed(int value) { list.buyItem(index, ItemCount.getInstance(value)); } }); } else { list.buyItem(index); } } } @NiftyEventSubscriber(id = "merchantDialog") public void handleMerchantCloseEvent(String topic, DialogMerchantCloseEvent event) { MerchantList list = World.getPlayer().getMerchantList(); if (list == null) { log.error("Close merchant list received, but there is not opened merchant list."); } else { list.closeDialog(); } lastMerchantTooltipItem = null; } @NiftyEventSubscriber(pattern = "inputDialog[0-9]+") public void handleInputConfirmedEvent(String topic, @Nonnull DialogInputConfirmedEvent event) { if (event.getPressedButton() == DialogButton.LeftButton) { World.getNet().sendCommand(new CloseDialogInputCmd(event.getDialogId(), event.getText(), true)); } else { World.getNet().sendCommand(new CloseDialogInputCmd(event.getDialogId(), "", false)); } } @NiftyEventSubscriber(pattern = "namingDialog[-0-9]+") public void handleNamingConfirmedEvent(String topic, @Nonnull DialogInputConfirmedEvent event) { if (event.getPressedButton() == DialogButton.LeftButton) { CharacterId id = new CharacterId(event.getDialogId()); String newName = event.getText(); World.getNet().sendCommand(new NamePlayerCmd(id, newName)); Char character = World.getPeople().getCharacter(id); if (character != null) { character.setCustomName(newName); } } } @NiftyEventSubscriber(pattern = "msgDialog[0-9]+") public void handleMessageConfirmedEvent(String topic, @Nonnull DialogMessageConfirmedEvent event) { World.getNet().sendCommand(new CloseDialogMessageCmd(event.getDialogId())); } @NiftyEventSubscriber(pattern = "selectDialog[0-9]+") public void handleSelectionCancelEvent(String topic, @Nonnull DialogSelectCancelEvent event) { World.getNet().sendCommand(new CloseDialogSelectionCmd(event.getDialogId(), 0, false)); World.getGameGui().getDialogGui().closeDialog(event.getDialogId(), EnumSet.of(DialogType.Selection)); } @NiftyEventSubscriber(pattern = "selectDialog[0-9]+") public void handleSelectionSelectEvent(String topic, @Nonnull DialogSelectSelectEvent event) { World.getNet().sendCommand(new CloseDialogSelectionCmd(event.getDialogId(), event.getItemIndex(), true)); World.getGameGui().getDialogGui().closeDialog(event.getDialogId(), EnumSet.of(DialogType.Selection)); } }