From c1b007d1a59abb35bc7ab4ebca6f572b0cdcc7c9 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Fri, 5 Nov 2021 20:56:59 +0000 Subject: [PATCH 1/5] feat(nui): convert the inventory screen to NUI --- .../game/screens/BuyItemsScreen.java | 67 +- .../game/screens/ChangeShipScreen.java | 65 +- .../game/screens/ChooseMercenaryScreen.java | 118 ++-- .../game/screens/GameScreens.java | 3 +- .../game/screens/GiveItemsScreen.java | 77 ++- .../game/screens/HireShipsScreen.java | 56 +- .../screens/InventoryOperationsScreen.java | 22 +- .../game/screens/InventoryScreen.java | 410 ------------- .../game/screens/SellItems.java | 76 ++- .../game/screens/ShowInventory.java | 160 +++-- .../game/screens/TakeItems.java | 62 +- .../game/screens/TalkScreen.java | 18 +- .../destinationsol/ui/TutorialManager.java | 63 +- .../org/destinationsol/ui/nui/NUIManager.java | 2 + .../destinationsol/ui/nui/NUIScreenLayer.java | 16 +- .../ui/nui/screens/InventoryScreen.java | 579 ++++++++++++++++++ .../ui/nui/screens/MainGameScreen.java | 18 +- .../ui/nui/widgets/KeyActivatedButton.java | 16 + .../ui/nui/widgets/UIWarnButton.java | 19 + .../assets/skins/inventoryScreen.skin | 24 + .../assets/skins/mainGameScreen.skin | 16 + .../assets/textures/ui/nui/background.png | Bin 0 -> 4881 bytes .../assets/ui/inventoryScreen.ui | 150 +++++ 23 files changed, 1326 insertions(+), 711 deletions(-) delete mode 100644 engine/src/main/java/org/destinationsol/game/screens/InventoryScreen.java create mode 100644 engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java create mode 100644 engine/src/main/resources/org/destinationsol/assets/skins/inventoryScreen.skin create mode 100644 engine/src/main/resources/org/destinationsol/assets/textures/ui/nui/background.png create mode 100644 engine/src/main/resources/org/destinationsol/assets/ui/inventoryScreen.ui diff --git a/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java b/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java index 702ef2ebb..ec8bc9a7b 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java @@ -16,7 +16,6 @@ package org.destinationsol.game.screens; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; import org.destinationsol.game.FactionInfo; import org.destinationsol.game.Hero; @@ -24,16 +23,37 @@ import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.UIWarnButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen allows you to purchase items for the hero's ship. + * The purchased items are moved to the hero's inventory and the cost deducted from the hero's money. + */ public class BuyItemsScreen extends InventoryOperationsScreen { - public final SolUiControl buyControl; + private final UIButton[] actionButtons = new UIButton[1]; + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + UIWarnButton buyButton = new UIWarnButton("buyButton", "Buy"); + buyButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyBuyItem())); + buyButton.subscribe(button -> { + SolGame game = solApplication.getGame(); + Hero hero = game.getHero(); + TalkScreen talkScreen = game.getScreens().talkScreen; + SolShip target = talkScreen.getTarget(); + SolItem selectedItem = inventoryScreen.getSelectedItem(); - BuyItemsScreen(InventoryScreen inventoryScreen, GameOptions gameOptions) { - buyControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyBuyItem()); - buyControl.setDisplayName("Buy"); - controls.add(buyControl); + target.getTradeContainer().getItems().remove(selectedItem); + hero.getItemContainer().add(selectedItem); + hero.setMoney(hero.getMoney() - selectedItem.getPrice()); + FactionInfo.setDisposition(target.getFactionID(), 1); + + inventoryScreen.updateItemRows(); + }); + actionButtons[0] = buyButton; } @Override @@ -47,28 +67,27 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + public UIWarnButton getBuyControl() { + return (UIWarnButton) actionButtons[0]; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen is = game.getScreens().inventoryScreen; Hero hero = game.getHero(); TalkScreen talkScreen = game.getScreens().talkScreen; - SolShip target = talkScreen.getTarget(); if (talkScreen.isTargetFar(hero)) { - solApplication.getInputManager().setScreen(solApplication, game.getScreens().mainGameScreen); + solApplication.getNuiManager().removeScreen(inventoryScreen); return; } - SolItem selItem = is.getSelectedItem(); + SolItem selItem = inventoryScreen.getSelectedItem(); boolean enabled = selItem != null && hero.getMoney() >= selItem.getPrice() && hero.getItemContainer().canAdd(selItem); - buyControl.setDisplayName(enabled ? "Buy" : "---"); - buyControl.setEnabled(enabled); - if (!enabled) { - return; - } - if (buyControl.isJustOff()) { - target.getTradeContainer().getItems().remove(selItem); - hero.getItemContainer().add(selItem); - hero.setMoney(hero.getMoney() - selItem.getPrice()); - FactionInfo.setDisposition(target.getFactionID(), 1); - } + UIButton buyButton = actionButtons[0]; + buyButton.setText(enabled ? "Buy" : "---"); + buyButton.setEnabled(enabled); } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/ChangeShipScreen.java b/engine/src/main/java/org/destinationsol/game/screens/ChangeShipScreen.java index 049ec0ac6..c0bcff042 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/ChangeShipScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/ChangeShipScreen.java @@ -16,7 +16,6 @@ package org.destinationsol.game.screens; import com.badlogic.gdx.math.Vector2; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; import org.destinationsol.game.Hero; import org.destinationsol.game.SolGame; @@ -29,16 +28,31 @@ import org.destinationsol.game.ship.SolShip; import org.destinationsol.game.ship.hulls.Hull; import org.destinationsol.game.ship.hulls.HullConfig; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen allows you to purchase a new ship for the hero. + * The hero's previous ship will be replaced with the purchased ship and the cost deducted from the hero's money. + */ public class ChangeShipScreen extends InventoryOperationsScreen { - private final SolUiControl changeControl; + private final UIButton[] actionButtons = new UIButton[1]; + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton changeButton = new KeyActivatedButton("changeButton", "Change"); + changeButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyChangeShip())); + changeButton.subscribe(button -> { + SolGame game = solApplication.getGame(); + Hero hero = game.getHero(); + SolItem selectedItem = inventoryScreen.getSelectedItem(); - ChangeShipScreen(InventoryScreen inventoryScreen, GameOptions gameOptions) { - changeControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyChangeShip()); - changeControl.setDisplayName("Change"); - controls.add(changeControl); + hero.setMoney(hero.getMoney() - selectedItem.getPrice()); + changeShip(game, hero, (ShipItem) selectedItem); + }); + actionButtons[0] = changeButton; } @Override @@ -52,38 +66,39 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen is = game.getScreens().inventoryScreen; Hero hero = game.getHero(); TalkScreen talkScreen = game.getScreens().talkScreen; if (talkScreen.isTargetFar(hero)) { solApplication.getInputManager().setScreen(solApplication, game.getScreens().mainGameScreen); return; } - SolItem selItem = is.getSelectedItem(); + + UIButton changeButton = actionButtons[0]; + + SolItem selItem = inventoryScreen.getSelectedItem(); if (selItem == null) { - changeControl.setDisplayName("---"); - changeControl.setEnabled(false); + changeButton.setText("---"); + changeButton.setEnabled(false); return; } boolean enabled = hasMoneyToBuyShip(hero, selItem); boolean sameShip = isSameShip(hero, selItem); if (enabled && !sameShip) { - changeControl.setDisplayName("Change"); - changeControl.setEnabled(true); + changeButton.setText("Change"); + changeButton.setEnabled(true); } else if (enabled && sameShip) { - changeControl.setDisplayName("Have it"); - changeControl.setEnabled(false); - return; + changeButton.setText("Have it"); + changeButton.setEnabled(false); } else { - changeControl.setDisplayName("---"); - changeControl.setEnabled(false); - return; - } - if (changeControl.isJustOff()) { - hero.setMoney(hero.getMoney() - selItem.getPrice()); - changeShip(game, hero, (ShipItem) selItem); + changeButton.setText("---"); + changeButton.setEnabled(false); } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/ChooseMercenaryScreen.java b/engine/src/main/java/org/destinationsol/game/screens/ChooseMercenaryScreen.java index 316021f2f..d18283521 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/ChooseMercenaryScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/ChooseMercenaryScreen.java @@ -15,7 +15,6 @@ */ package org.destinationsol.game.screens; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; import org.destinationsol.game.SolGame; import org.destinationsol.game.item.ItemContainer; @@ -23,60 +22,85 @@ import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen shows an overview of all the mercenaries that the hero has hired. + * You can manage each mercenary's independent inventory from here, as well as selecting their equipped items. + */ public class ChooseMercenaryScreen extends InventoryOperationsScreen { - private final SolUiControl giveControl; - private final SolUiControl takeControl; - private final SolUiControl equipControl; + private final UIButton[] actionButtons = new UIButton[3]; private final ItemContainer EMPTY_ITEM_CONTAINER = new ItemContainer(); - ChooseMercenaryScreen(InventoryScreen inventoryScreen, GameOptions gameOptions) { - giveControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyShoot()); - giveControl.setDisplayName("Give Items"); - controls.add(giveControl); + public ChooseMercenaryScreen() { + } + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton giveButton = new KeyActivatedButton("giveButton", "Give Items"); + giveButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot())); + giveButton.subscribe(button -> { + SolItem selectedItem = inventoryScreen.getSelectedItem(); + SolInputManager inputManager = solApplication.getInputManager(); + NUIManager nuiManager = solApplication.getNuiManager(); + + SolShip solship = ((MercItem) selectedItem).getSolShip(); + inputManager.setScreen(solApplication, solApplication.getGame().getScreens().mainGameScreen); + nuiManager.removeScreen(inventoryScreen); + inventoryScreen.getGiveItems().setTarget(solship); + inventoryScreen.setOperations(inventoryScreen.getGiveItems()); + nuiManager.pushScreen(inventoryScreen); + }); + actionButtons[0] = giveButton; + + KeyActivatedButton takeButton = new KeyActivatedButton("takeButton", "Take Items"); + takeButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot2())); + takeButton.subscribe(button -> { + SolItem selectedItem = inventoryScreen.getSelectedItem(); + SolInputManager inputManager = solApplication.getInputManager(); + NUIManager nuiManager = solApplication.getNuiManager(); - takeControl = new SolUiControl(inventoryScreen.itemCtrl(1), true, gameOptions.getKeyShoot2()); - takeControl.setDisplayName("Take Items"); - controls.add(takeControl); - - equipControl = new SolUiControl(inventoryScreen.itemCtrl(2), true, gameOptions.getKeyDrop()); - equipControl.setDisplayName("Equip Items"); - controls.add(equipControl); + SolShip solship = ((MercItem) selectedItem).getSolShip(); + inputManager.setScreen(solApplication, solApplication.getGame().getScreens().mainGameScreen); + inventoryScreen.getTakeItems().setTarget(solship); + nuiManager.removeScreen(inventoryScreen); + inventoryScreen.setOperations(inventoryScreen.getTakeItems()); + nuiManager.pushScreen(inventoryScreen); + }); + actionButtons[1] = takeButton; + + KeyActivatedButton equipButton = new KeyActivatedButton("equipButton", "Equip Items"); + equipButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyDrop())); + equipButton.subscribe(button -> { + SolItem selectedItem = inventoryScreen.getSelectedItem(); + SolInputManager inputManager = solApplication.getInputManager(); + NUIManager nuiManager = solApplication.getNuiManager(); + + SolShip solship = ((MercItem) selectedItem).getSolShip(); + inputManager.setScreen(solApplication, solApplication.getGame().getScreens().mainGameScreen); + nuiManager.removeScreen(inventoryScreen); + inventoryScreen.getShowInventory().setTarget(solship); + inventoryScreen.setOperations(inventoryScreen.getShowInventory()); + nuiManager.pushScreen(inventoryScreen); + }); + actionButtons[2] = equipButton; } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - SolGame game = solApplication.getGame(); - InventoryScreen is = game.getScreens().inventoryScreen; - SolInputManager inputMan = solApplication.getInputManager(); - GameScreens screens = game.getScreens(); - SolItem selItem = is.getSelectedItem(); - boolean selNull = selItem != null; + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { + boolean selNull = inventoryScreen.getSelectedItem() != null; - giveControl.setEnabled(selNull); - takeControl.setEnabled(selNull); - equipControl.setEnabled(selNull); + UIButton giveButton = actionButtons[0]; + UIButton takeButton = actionButtons[1]; + UIButton equipButton = actionButtons[2]; - if (giveControl.isJustOff() && selNull) { - SolShip solship = ((MercItem) selItem).getSolShip(); - inputMan.setScreen(solApplication, screens.mainGameScreen); - is.giveItemsScreen.setTarget(solship); - is.setOperations(is.giveItemsScreen); - inputMan.addScreen(solApplication, is); - } else if (takeControl.isJustOff() && selNull) { - SolShip solship = ((MercItem) selItem).getSolShip(); - inputMan.setScreen(solApplication, screens.mainGameScreen); - is.takeItems.setTarget(solship); - is.setOperations(is.takeItems); - inputMan.addScreen(solApplication, is); - } else if (equipControl.isJustOff() && selNull) { - SolShip solship = ((MercItem) selItem).getSolShip(); - inputMan.setScreen(solApplication, screens.mainGameScreen); - is.showInventory.setTarget(solship); - is.setOperations(is.showInventory); - inputMan.addScreen(solApplication, is); - } + giveButton.setEnabled(selNull); + takeButton.setEnabled(selNull); + equipButton.setEnabled(selNull); } @Override @@ -95,4 +119,8 @@ public String getHeader() { return "Mercenaries:"; } + @Override + public UIButton[] getActionButtons() { + return actionButtons; + } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java b/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java index 8ea147dbd..c5178173a 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java +++ b/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java @@ -18,6 +18,7 @@ import org.destinationsol.SolApplication; import org.destinationsol.game.context.Context; import org.destinationsol.ui.SolLayouts; +import org.destinationsol.ui.nui.screens.InventoryScreen; public class GameScreens { public final MainGameScreen mainGameScreen; @@ -34,7 +35,7 @@ public GameScreens(SolApplication cmp, Context context) { mainGameScreen = new MainGameScreen(rightPaneLayout, context); mapScreen = new MapScreen(rightPaneLayout, cmp.isMobile(), cmp.getOptions()); menuScreen = new MenuScreen(layouts.menuLayout, cmp.getOptions()); - inventoryScreen = new InventoryScreen(cmp.getOptions()); + inventoryScreen = (org.destinationsol.ui.nui.screens.InventoryScreen) cmp.getNuiManager().createScreen("engine:inventoryScreen"); talkScreen = new TalkScreen(layouts.menuLayout, cmp.getOptions()); waypointCreationScreen = new WaypointCreationScreen(layouts.menuLayout, cmp.getOptions(), mapScreen); consoleScreen = new ConsoleScreen(context); diff --git a/engine/src/main/java/org/destinationsol/game/screens/GiveItemsScreen.java b/engine/src/main/java/org/destinationsol/game/screens/GiveItemsScreen.java index b0862faa1..eb98224a9 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/GiveItemsScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/GiveItemsScreen.java @@ -22,17 +22,36 @@ import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen allows the hero to gift items from their inventory to the targeted mercenary. + */ public class GiveItemsScreen extends InventoryOperationsScreen { - private final SolUiControl giveControl; + private final UIButton[] actionButtons = new UIButton[1]; private SolShip target; - GiveItemsScreen(InventoryScreen inventoryScreen, GameOptions gameOptions) { - giveControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeySellItem()); - giveControl.setDisplayName("Give"); - controls.add(giveControl); + public GiveItemsScreen() { + } + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton giveButton = new KeyActivatedButton("giveButton", "Give"); + giveButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeySellItem())); + giveButton.subscribe(button -> { + Hero hero = solApplication.getGame().getHero(); + SolItem selectedItem = inventoryScreen.getSelectedItem(); + + ItemContainer itemContainer = hero.getItemContainer(); + inventoryScreen.setSelected(itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected())); + itemContainer.remove(selectedItem); + target.getItemContainer().add(selectedItem); + inventoryScreen.updateItemRows(); + }); + actionButtons[0] = giveButton; } @Override @@ -53,40 +72,36 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen inventoryScreen = game.getScreens().inventoryScreen; Hero hero = game.getHero(); - SolItem selItem = inventoryScreen.getSelectedItem(); - if (selItem == null) { - giveControl.setDisplayName("----"); - giveControl.setEnabled(false); + UIButton giveButton = actionButtons[0]; + + SolItem selectedItem = inventoryScreen.getSelectedItem(); + if (selectedItem == null) { + giveButton.setText("----"); + giveButton.setEnabled(false); return; } - boolean isWornAndCanBeGiven = isItemEquippedAndGiveable(selItem, solApplication.getOptions()); - boolean enabled = isItemGiveable(selItem, target); + boolean isWornAndCanBeGiven = isItemEquippedAndGiveable(selectedItem, solApplication.getOptions()); + boolean enabled = isItemGiveable(selectedItem, target); if (enabled && isWornAndCanBeGiven) { - giveControl.setDisplayName("Give"); - giveControl.setEnabled(true); + giveButton.setText("Give"); + giveButton.setEnabled(true); } else if (enabled) { - giveControl.setDisplayName("Unequip it!"); - giveControl.setEnabled(false); + giveButton.setText("Unequip it!"); + giveButton.setEnabled(false); } else { - giveControl.setDisplayName("----"); - giveControl.setEnabled(false); - } - - if (!enabled || !isWornAndCanBeGiven) { - return; - } - if (giveControl.isJustOff()) { - ItemContainer itemContainer = hero.getItemContainer(); - inventoryScreen.setSelected(itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected())); - itemContainer.remove(selItem); - target.getItemContainer().add(selItem); + giveButton.setText("----"); + giveButton.setEnabled(false); } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/HireShipsScreen.java b/engine/src/main/java/org/destinationsol/game/screens/HireShipsScreen.java index 613776671..e34745ab0 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/HireShipsScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/HireShipsScreen.java @@ -15,7 +15,6 @@ */ package org.destinationsol.game.screens; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; import org.destinationsol.game.Hero; import org.destinationsol.game.SolGame; @@ -23,16 +22,32 @@ import org.destinationsol.game.item.MercItem; import org.destinationsol.game.item.SolItem; import org.destinationsol.mercenary.MercenaryUtils; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; public class HireShipsScreen extends InventoryOperationsScreen { - private final SolUiControl hireControl; + private final UIButton[] actionButtons = new UIButton[1]; - HireShipsScreen(InventoryScreen inventoryScreen, GameOptions gameOptions) { - hireControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyHireShip()); - hireControl.setDisplayName("Hire"); - controls.add(hireControl); + public HireShipsScreen() { + } + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton hireButton = new KeyActivatedButton(); + hireButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyHireShip())); + hireButton.subscribe(button -> { + SolGame game = solApplication.getGame(); + Hero hero = game.getHero(); + SolItem selectedItem = inventoryScreen.getSelectedItem(); + + boolean hired = MercenaryUtils.createMerc(game, hero, (MercItem) selectedItem); + if (hired) { + hero.setMoney(hero.getMoney() - selectedItem.getPrice()); + } + }); + actionButtons[0] = hireButton; } @Override @@ -46,27 +61,24 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen is = game.getScreens().inventoryScreen; Hero hero = game.getHero(); TalkScreen talkScreen = game.getScreens().talkScreen; if (talkScreen.isTargetFar(hero)) { solApplication.getInputManager().setScreen(solApplication, game.getScreens().mainGameScreen); return; } - SolItem selItem = is.getSelectedItem(); + + UIButton hireButton = actionButtons[0]; + SolItem selItem = inventoryScreen.getSelectedItem(); boolean enabled = selItem != null && hero.getMoney() >= selItem.getPrice(); - hireControl.setDisplayName(enabled ? "Hire" : "---"); - hireControl.setEnabled(enabled); - if (!enabled) { - return; - } - if (hireControl.isJustOff()) { - boolean hired = MercenaryUtils.createMerc(game, hero, (MercItem) selItem); - if (hired) { - hero.setMoney(hero.getMoney() - selItem.getPrice()); - } - } + hireButton.setText(enabled ? "Hire" : "---"); + hireButton.setEnabled(enabled); } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/InventoryOperationsScreen.java b/engine/src/main/java/org/destinationsol/game/screens/InventoryOperationsScreen.java index bffc7b70d..456994790 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/InventoryOperationsScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/InventoryOperationsScreen.java @@ -15,21 +15,35 @@ */ package org.destinationsol.game.screens; +import org.destinationsol.SolApplication; import org.destinationsol.game.SolGame; import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.ui.SolUiBaseScreen; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.terasology.nui.widgets.UIButton; +/** + * This is the base class for all inventory operations. + */ public abstract class InventoryOperationsScreen extends SolUiBaseScreen { - abstract ItemContainer getItems(SolGame game); + public abstract ItemContainer getItems(SolGame game); - boolean isUsing(SolGame game, SolItem item) { + public boolean isUsing(SolGame game, SolItem item) { return false; } - float getPriceMul() { + public float getPriceMul() { return 1; } - abstract String getHeader(); + public abstract String getHeader(); + + public abstract UIButton[] getActionButtons(); + + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + } + + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { + } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/InventoryScreen.java b/engine/src/main/java/org/destinationsol/game/screens/InventoryScreen.java deleted file mode 100644 index cddbe0686..000000000 --- a/engine/src/main/java/org/destinationsol/game/screens/InventoryScreen.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.game.screens; - -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.math.Rectangle; -import com.badlogic.gdx.math.Vector2; -import org.destinationsol.Const; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.SolGame; -import org.destinationsol.game.item.ItemContainer; -import org.destinationsol.game.item.SolItem; -import org.destinationsol.menu.MenuLayout; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -import java.util.ArrayList; -import java.util.List; - -public class InventoryScreen extends SolUiBaseScreen { - // TODO: Rename! - private static final ItemContainer EMPTY_CONTAINER = new ItemContainer(); - private static final float HEADER_TEXT_OFFSET = .005f; - private static final float SMALL_GAP = .004f; - private static final int BUTTON_ROWS = 4; - private static final float IMG_COL_PERC = .1f; - private static final float EQUI_COL_PERC = .1f; - private static final float PRICE_COL_PERC = .1f; - private static final float AMT_COL_PERC = .1f; - - public final ShowInventory showInventory; - public final BuyItemsScreen buyItemsScreen; - public final SellItems sellItems; - public final ChangeShipScreen changeShipScreen; - public final HireShipsScreen hireShipsScreen; - // The below screens deal with mercenaries - public final ChooseMercenaryScreen chooseMercenaryScreen; - public final GiveItemsScreen giveItemsScreen; - public final TakeItems takeItems; - - public final SolUiControl[] itemControls; - private final SolUiControl previousControl; - private final SolUiControl upControl; - public final SolUiControl nextControl; - public final SolUiControl closeControl; - public final SolUiControl downControl; - - private final Rectangle myArea; - private final Rectangle myListArea; - private final Rectangle myDetailArea; - private final Rectangle myItemCtrlArea; - private final Vector2 myDetailHeaderPos; - private final Vector2 myListHeaderPos; - - private int myPage; - private List mySelected; - private InventoryOperationsScreen myOperations; - - public InventoryScreen(GameOptions gameOptions) { - DisplayDimensions displayDimensions = SolApplication.displayDimensions; - - float contentW = .8f; - float col0 = displayDimensions.getRatio() / 2 - contentW / 2; - float row0 = .2f; - float row = row0; - float backgroundGap = MenuLayout.BG_BORDER; - float bigGap = SMALL_GAP * 6; - float headerH = .03f; - - // list header & controls - myListHeaderPos = new Vector2(col0 + HEADER_TEXT_OFFSET, row + HEADER_TEXT_OFFSET); // offset hack - float listCtrlW = contentW * .15f; - Rectangle nextArea = new Rectangle(col0 + contentW - listCtrlW, row, listCtrlW, headerH); - nextControl = new SolUiControl(nextArea, true, gameOptions.getKeyRight()); - nextControl.setDisplayName(">"); - controls.add(nextControl); - Rectangle prevArea = new Rectangle(nextArea.x - SMALL_GAP - listCtrlW, row, listCtrlW, headerH); - previousControl = new SolUiControl(prevArea, true, gameOptions.getKeyLeft()); - previousControl.setDisplayName("<"); - controls.add(previousControl); - row += headerH + SMALL_GAP; - - // list - float itemRowH = .04f; - float listRow0 = row; - itemControls = new SolUiControl[Const.ITEM_GROUPS_PER_PAGE]; - for (int i = 0; i < Const.ITEM_GROUPS_PER_PAGE; i++) { - Rectangle itemR = new Rectangle(col0, row, contentW, itemRowH); - SolUiControl itemCtrl = new SolUiControl(itemR, true); - itemControls[i] = itemCtrl; - controls.add(itemCtrl); - row += itemRowH + SMALL_GAP; - } - myListArea = new Rectangle(col0, row, contentW, row - SMALL_GAP - listRow0); - row += bigGap; - - // detail header & area - myDetailHeaderPos = new Vector2(col0 + HEADER_TEXT_OFFSET, row + HEADER_TEXT_OFFSET); // offset hack - row += headerH + SMALL_GAP; - float itemCtrlAreaW = contentW * .4f; - myItemCtrlArea = new Rectangle(col0 + contentW - itemCtrlAreaW, row, itemCtrlAreaW, .2f); - myDetailArea = new Rectangle(col0, row, contentW - itemCtrlAreaW - SMALL_GAP, myItemCtrlArea.height); - row += myDetailArea.height; - - // whole - myArea = new Rectangle(col0 - backgroundGap, row0 - backgroundGap, contentW + backgroundGap * 2, row - row0 + backgroundGap * 2); - - closeControl = new SolUiControl(itemCtrl(3), true, gameOptions.getKeyClose()); - closeControl.setDisplayName("Close"); - controls.add(closeControl); - - showInventory = new ShowInventory(this, gameOptions); - buyItemsScreen = new BuyItemsScreen(this, gameOptions); - sellItems = new SellItems(this, gameOptions); - changeShipScreen = new ChangeShipScreen(this, gameOptions); - hireShipsScreen = new HireShipsScreen(this, gameOptions); - chooseMercenaryScreen = new ChooseMercenaryScreen(this, gameOptions); - giveItemsScreen = new GiveItemsScreen(this, gameOptions); - takeItems = new TakeItems(this, gameOptions); - upControl = new SolUiControl(null, true, gameOptions.getKeyUp()); - controls.add(upControl); - downControl = new SolUiControl(null, true, gameOptions.getKeyDown()); - controls.add(downControl); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - if (clickedOutside) { - closeControl.maybeFlashPressed(solApplication.getOptions().getKeyClose()); - return; - } - if (closeControl.isJustOff()) { - - SolGame game = solApplication.getGame(); - // Make sure the ChooseMercenaryScreen screen comes back up when we exit a mercenary related screen - if (myOperations == giveItemsScreen || myOperations == takeItems || (myOperations == showInventory && showInventory.getTarget() != game.getHero().getShip())) { - SolInputManager inputMan = solApplication.getInputManager(); - GameScreens screens = game.getScreens(); - InventoryScreen is = screens.inventoryScreen; - - inputMan.setScreen(solApplication, screens.mainGameScreen); - is.setOperations(is.chooseMercenaryScreen); - inputMan.addScreen(solApplication, is); - } - solApplication.getInputManager().setScreen(solApplication, solApplication.getGame().getScreens().mainGameScreen); - return; - } - if (previousControl.isJustOff()) { - myPage--; - } - if (nextControl.isJustOff()) { - myPage++; - } - - ItemContainer itemContainer = myOperations.getItems(solApplication.getGame()); - if (itemContainer == null) { - itemContainer = EMPTY_CONTAINER; - } - int groupCount = itemContainer.groupCount(); - int pageCount = groupCount / Const.ITEM_GROUPS_PER_PAGE; - if (pageCount == 0 || pageCount * Const.ITEM_GROUPS_PER_PAGE < groupCount) { - pageCount += 1; - } - if (myPage < 0) { - myPage = 0; - } - if (myPage >= pageCount) { - myPage = pageCount - 1; - } - - previousControl.setEnabled(0 < myPage); - nextControl.setEnabled(myPage < pageCount - 1); - - if (!itemContainer.containsGroup(mySelected)) { - mySelected = null; - } - int selIdx = -1; - int offset = myPage * Const.ITEM_GROUPS_PER_PAGE; - boolean hNew = showingHeroItems(solApplication); - for (int i = 0; i < itemControls.length; i++) { - SolUiControl itemCtrl = itemControls[i]; - int groupIdx = offset + i; - boolean ctrlEnabled = groupIdx < groupCount; - itemCtrl.setEnabled(ctrlEnabled); - if (!ctrlEnabled) { - continue; - } - List group = itemContainer.getGroup(groupIdx); - if (hNew && itemContainer.isNew(group)) { - itemCtrl.enableWarn(); - } - if (itemCtrl.isJustOff()) { - mySelected = group; - } - if (mySelected == group) { - selIdx = groupIdx; - } - } - if (selIdx < 0 && groupCount > 0) { - mySelected = itemContainer.getGroup(offset); - } - if (upControl.isJustOff() && selIdx > 0) { - selIdx--; - mySelected = itemContainer.getGroup(selIdx); - if (selIdx < offset) { - myPage--; - } - } - if (downControl.isJustOff() && selIdx < groupCount - 1) { - selIdx++; - mySelected = itemContainer.getGroup(selIdx); - if (selIdx >= offset + Const.ITEM_GROUPS_PER_PAGE) { - myPage++; - } - } - if (mySelected != null) { - itemContainer.seen(mySelected); - } - } - - @Override - public boolean isCursorOnBackground(SolInputManager.InputPointer inputPointer) { - return myArea.contains(inputPointer.x, inputPointer.y); - } - - @Override - public void onAdd(SolApplication solApplication) { - if (myOperations != null) { - solApplication.getInputManager().addScreen(solApplication, myOperations); - } - myPage = 0; - mySelected = null; - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(myArea, SolColor.UI_BG); - } - - @Override - public void drawImages(UiDrawer uiDrawer, SolApplication solApplication) { - SolGame game = solApplication.getGame(); - ItemContainer itemContainer = myOperations.getItems(game); - if (itemContainer == null) { - itemContainer = EMPTY_CONTAINER; - } - - float imgColW = myListArea.width * IMG_COL_PERC; - float rowH = itemControls[0].getScreenArea().height; - float imgSz = imgColW < rowH ? imgColW : rowH; - - uiDrawer.draw(myDetailArea, SolColor.UI_INACTIVE); - for (int i = 0; i < itemControls.length; i++) { - int groupIdx = myPage * Const.ITEM_GROUPS_PER_PAGE + i; - int groupCount = itemContainer.groupCount(); - if (groupCount <= groupIdx) { - continue; - } - SolUiControl itemCtrl = itemControls[i]; - List group = itemContainer.getGroup(groupIdx); - SolItem item = group.get(0); - TextureAtlas.AtlasRegion tex = item.getIcon(game); - Rectangle rect = itemCtrl.getScreenArea(); - float rowCenterY = rect.y + rect.height / 2; - uiDrawer.draw(uiDrawer.whiteTexture, imgSz, imgSz, imgSz / 2, imgSz / 2, rect.x + imgColW / 2, rowCenterY, 0, item.getItemType().uiColor); - uiDrawer.draw(tex, imgSz, imgSz, imgSz / 2, imgSz / 2, rect.x + imgColW / 2, rowCenterY, 0, SolColor.WHITE); - } - } - - @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - SolGame game = solApplication.getGame(); - ItemContainer itemContainer = myOperations.getItems(game); - if (itemContainer == null) { - itemContainer = EMPTY_CONTAINER; - } - - float imgColW = myListArea.width * IMG_COL_PERC; - float equiColW = myListArea.width * EQUI_COL_PERC; - float priceWidth = myListArea.width * PRICE_COL_PERC; - float amtWidth = myListArea.width * AMT_COL_PERC; - float nameWidth = myListArea.width - imgColW - equiColW - priceWidth - amtWidth; - for (int i = 0; i < itemControls.length; i++) { - int groupIdx = myPage * Const.ITEM_GROUPS_PER_PAGE + i; - int groupCount = itemContainer.groupCount(); - if (groupCount <= groupIdx) { - continue; - } - SolUiControl itemCtrl = itemControls[i]; - List group = itemContainer.getGroup(groupIdx); - SolItem item = group.get(0); - Rectangle rect = itemCtrl.getScreenArea(); - float rowCenterY = rect.y + rect.height / 2; - if (myOperations.isUsing(game, item)) { - uiDrawer.drawString("using", rect.x + imgColW + equiColW / 2, rowCenterY, FontSize.WINDOW, true, SolColor.WHITE); - } - uiDrawer.drawString(item.getDisplayName(), rect.x + equiColW + imgColW + nameWidth / 2, rowCenterY, FontSize.WINDOW, true, - mySelected == group ? SolColor.WHITE : SolColor.G); - int count = itemContainer.getCount(groupIdx); - if (count > 1) { - uiDrawer.drawString("x" + count, rect.x + rect.width - amtWidth / 2, rowCenterY, FontSize.WINDOW, true, SolColor.WHITE); - } - float mul = myOperations.getPriceMul(); - if (mul > 0) { - float price = item.getPrice() * mul; - uiDrawer.drawString("$" + (int) price, rect.x + rect.width - amtWidth - priceWidth / 2, rowCenterY, FontSize.WINDOW, true, SolColor.LG); - } - } - - uiDrawer.drawString(myOperations.getHeader(), myListHeaderPos.x, myListHeaderPos.y, FontSize.WINDOW, UiDrawer.TextAlignment.LEFT, false, SolColor.WHITE); - uiDrawer.drawString("Selected Item:", myDetailHeaderPos.x, myDetailHeaderPos.y, FontSize.WINDOW, UiDrawer.TextAlignment.LEFT, false, SolColor.WHITE); - if (mySelected != null && !mySelected.isEmpty()) { - SolItem selItem = mySelected.get(0); - String desc = selItem.getDisplayName() + "\n" + selItem.getDescription(); - uiDrawer.drawString(desc, myDetailArea.x + .015f, myDetailArea.y + .015f, FontSize.WINDOW, UiDrawer.TextAlignment.LEFT, false, SolColor.WHITE); - } - } - - @Override - public boolean reactsToClickOutside() { - return true; - } - - @Override - public void blurCustom(SolApplication solApplication) { - if (!showingHeroItems(solApplication)) { - return; - } - SolGame game = solApplication.getGame(); - ItemContainer items = myOperations.getItems(game); - if (items != null) { - items.markAllAsSeen(); - } - } - - private boolean showingHeroItems(SolApplication application) { - return application.getGame().getHero().getShip() == showInventory.getTarget() || myOperations == sellItems; - } - - public Rectangle itemCtrl(int row) { - float h = (myItemCtrlArea.height - SMALL_GAP * (BUTTON_ROWS - 1)) / BUTTON_ROWS; - return new Rectangle(myItemCtrlArea.x, myItemCtrlArea.y + (h + SMALL_GAP) * row, myItemCtrlArea.width, h); - } - - public List getSelected() { - return mySelected; - } - - public void setSelected(List selected) { - mySelected = selected; - } - - public SolItem getSelectedItem() { - return mySelected == null || mySelected.isEmpty() ? null : mySelected.get(0); - } - - public InventoryOperationsScreen getOperations() { - return myOperations; - } - - public void setOperations(InventoryOperationsScreen operations) { - myOperations = operations; - } - - public int getPage() { - return myPage; - } - - public List getEquippedItemUIControlsForTutorial(SolGame game) { - List controls = new ArrayList<>(); - ItemContainer itemContainer = myOperations.getItems(game); - if (itemContainer == null) { - return controls; - } - - for (int i = 0; i < itemControls.length; i++) { - int groupIdx = myPage * Const.ITEM_GROUPS_PER_PAGE + i; - int groupCount = itemContainer.groupCount(); - if (groupCount <= groupIdx) { - continue; - } - SolUiControl itemCtrl = itemControls[i]; - List group = itemContainer.getGroup(groupIdx); - SolItem item = group.get(0); - if (myOperations.isUsing(game, item)) { - controls.add(itemCtrl); - } - } - return controls; - } -} diff --git a/engine/src/main/java/org/destinationsol/game/screens/SellItems.java b/engine/src/main/java/org/destinationsol/game/screens/SellItems.java index bd02e33e6..60dc0cc9f 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/SellItems.java +++ b/engine/src/main/java/org/destinationsol/game/screens/SellItems.java @@ -22,18 +22,43 @@ import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen allows the hero to sell their items in exchange for in-game currency (money). + * The sold items are moved into the vendor's inventory. + */ public class SellItems extends InventoryOperationsScreen { private static float PERC = .8f; - private final SolUiControl sellControl; + private final UIButton[] actionButtons = new UIButton[1]; - SellItems(InventoryScreen inventoryScreen, GameOptions gameOptions) { - sellControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeySellItem()); - sellControl.setDisplayName("Sell"); - controls.add(sellControl); + public SellItems() { + } + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton sellButton = new KeyActivatedButton("sellButton", "Sell"); + sellButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeySellItem())); + sellButton.subscribe(button -> { + SolGame game = solApplication.getGame(); + Hero hero = game.getHero(); + SolItem selectedItem = inventoryScreen.getSelectedItem(); + TalkScreen talkScreen = game.getScreens().talkScreen; + SolShip target = talkScreen.getTarget(); + + ItemContainer itemContainer = hero.getItemContainer(); + inventoryScreen.setSelected(itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected())); + itemContainer.remove(selectedItem); + target.getTradeContainer().getItems().add(selectedItem); + hero.setMoney(hero.getMoney() + selectedItem.getPrice() * PERC); + + inventoryScreen.updateItemRows(); + }); + actionButtons[0] = sellButton; } @Override @@ -59,9 +84,15 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen inventoryScreen = game.getScreens().inventoryScreen; + UIButton sellButton = actionButtons[0]; + TalkScreen talkScreen = game.getScreens().talkScreen; SolShip target = talkScreen.getTarget(); Hero hero = game.getHero(); @@ -71,8 +102,8 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi } SolItem selItem = inventoryScreen.getSelectedItem(); if (selItem == null) { - sellControl.setDisplayName("----"); - sellControl.setEnabled(false); + sellButton.setText("----"); + sellButton.setEnabled(false); return; } @@ -80,25 +111,14 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi boolean enabled = isItemSellable(selItem, target); if (enabled && isWornAndCanBeSold) { - sellControl.setDisplayName("Sell"); - sellControl.setEnabled(true); + sellButton.setText("Sell"); + sellButton.setEnabled(true); } else if (enabled) { - sellControl.setDisplayName("Unequip it!"); - sellControl.setEnabled(false); + sellButton.setText("Unequip it!"); + sellButton.setEnabled(false); } else { - sellControl.setDisplayName("----"); - sellControl.setEnabled(false); - } - - if (!enabled || !isWornAndCanBeSold) { - return; - } - if (sellControl.isJustOff()) { - ItemContainer itemContainer = hero.getItemContainer(); - inventoryScreen.setSelected(itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected())); - itemContainer.remove(selItem); - target.getTradeContainer().getItems().add(selItem); - hero.setMoney(hero.getMoney() + selItem.getPrice() * PERC); + sellButton.setText("----"); + sellButton.setEnabled(false); } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/ShowInventory.java b/engine/src/main/java/org/destinationsol/game/screens/ShowInventory.java index 07d8dba0a..6d56b4e2b 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/ShowInventory.java +++ b/engine/src/main/java/org/destinationsol/game/screens/ShowInventory.java @@ -23,79 +23,76 @@ import org.destinationsol.game.ship.SolShip; import org.destinationsol.ui.SolInputManager; import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.destinationsol.ui.nui.widgets.UIWarnButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +import java.util.List; + +/** + * This screen shows the current inventory of the targeted ship. + * You can also equip and de-equip items here, as well as force the ship to drop those items out into space. + */ public class ShowInventory extends InventoryOperationsScreen { - public final SolUiControl eq1Control; - private final SolUiControl eq2Control; - public final SolUiControl dropControl; - + private final UIButton[] actionButtons = new UIButton[3]; + private SolShip target; - ShowInventory(InventoryScreen inventoryScreen, GameOptions gameOptions) { - eq1Control = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyEquip()); - eq1Control.setDisplayName("Eq"); - controls.add(eq1Control); - - eq2Control = new SolUiControl(inventoryScreen.itemCtrl(1), true, gameOptions.getKeyEquip2()); - eq2Control.setDisplayName("Eq2"); - controls.add(eq2Control); - - dropControl = new SolUiControl(inventoryScreen.itemCtrl(2), true, gameOptions.getKeyDrop()); - dropControl.setDisplayName("Drop"); - controls.add(dropControl); + public ShowInventory() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - SolGame game = solApplication.getGame(); - InventoryScreen inventoryScreen = game.getScreens().inventoryScreen; - SolItem selItem = inventoryScreen.getSelectedItem(); - - eq1Control.setDisplayName("---"); - eq1Control.setEnabled(false); - eq2Control.setDisplayName("---"); - eq2Control.setEnabled(false); - dropControl.setEnabled(false); - - if (selItem == null || target == null) { - return; - } - - dropControl.setEnabled(true); - if (dropControl.isJustOff()) { - ItemContainer itemContainer = target.getItemContainer(); - inventoryScreen.setSelected(itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected())); - target.dropItem(solApplication.getGame(), selItem); - return; - } + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + GameOptions gameOptions = solApplication.getOptions(); - Boolean equipped1 = target.maybeUnequip(game, selItem, false, false); - boolean canEquip1 = target.maybeEquip(game, selItem, false, false); - Boolean equipped2 = target.maybeUnequip(game, selItem, true, false); - boolean canEquip2 = target.maybeEquip(game, selItem, true, false); + UIWarnButton equip1Button = new UIWarnButton("equip1Button", "Eq"); + equip1Button.setKey(GDXInputUtil.GDXToNuiKey(gameOptions.getKeyEquip())); + equip1Button.subscribe(button -> { + SolGame game = solApplication.getGame(); + SolItem selItem = inventoryScreen.getSelectedItem(); + if (selItem == null) { + button.setEnabled(false); + return; + } - if (equipped1 || canEquip1) { - eq1Control.setDisplayName(equipped1 ? "Unequip" : "Equip"); - eq1Control.setEnabled(true); - } - if (equipped2 || canEquip2) { - eq2Control.setDisplayName(equipped2 ? "Unequip" : "Set Gun 2"); - eq2Control.setEnabled(true); - } - if (eq1Control.isJustOff()) { - if (equipped1) { + if (target.maybeUnequip(game, selItem, false, false)) { target.maybeUnequip(game, selItem, false, true); } else { target.maybeEquip(game, selItem, false, true); } - } - if (eq2Control.isJustOff()) { - if (equipped2) { + inventoryScreen.updateItemRows(); + }); + + UIWarnButton equip2Button = new UIWarnButton("equip2Button", "Eq2"); + equip2Button.setKey(GDXInputUtil.GDXToNuiKey(gameOptions.getKeyEquip2())); + equip2Button.subscribe(button -> { + SolGame game = solApplication.getGame(); + SolItem selItem = inventoryScreen.getSelectedItem(); + if (target.maybeUnequip(game, selItem, true, false)) { target.maybeUnequip(game, selItem, true, true); } else { target.maybeEquip(game, selItem, true, true); } - } + inventoryScreen.updateItemRows(); + }); + + UIWarnButton dropButton = new UIWarnButton("dropButton", "Drop"); + dropButton.setKey(GDXInputUtil.GDXToNuiKey(gameOptions.getKeyDrop())); + dropButton.subscribe(button -> { + SolItem selItem = inventoryScreen.getSelectedItem(); + ItemContainer itemContainer = target.getItemContainer(); + List newSelection = itemContainer.getSelectionAfterRemove(inventoryScreen.getSelected()); + target.dropItem(solApplication.getGame(), selItem); + inventoryScreen.updateItemRows(); + + inventoryScreen.setSelected(newSelection); + }); + + actionButtons[0] = equip1Button; + actionButtons[1] = equip2Button; + actionButtons[2] = dropButton; } @Override @@ -117,7 +114,56 @@ public float getPriceMul() { public String getHeader() { return "Items:"; } - + + @Override + public UIButton[] getActionButtons() { + return actionButtons; + } + + public UIWarnButton getEq1Control() { + return (UIWarnButton) actionButtons[0]; + } + + public UIWarnButton getDropControl() { + return (UIWarnButton) actionButtons[2]; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { + SolGame game = solApplication.getGame(); + SolItem selItem = inventoryScreen.getSelectedItem(); + + UIButton equip1Button = actionButtons[0]; + UIButton equip2Button = actionButtons[1]; + UIButton dropButton = actionButtons[2]; + + equip1Button.setText("---"); + equip1Button.setEnabled(false); + equip2Button.setText("---"); + equip2Button.setEnabled(false); + dropButton.setEnabled(false); + + if (selItem == null || target == null) { + return; + } + + dropButton.setEnabled(true); + + boolean equipped1 = target.maybeUnequip(game, selItem, false, false); + boolean canEquip1 = target.maybeEquip(game, selItem, false, false); + boolean equipped2 = target.maybeUnequip(game, selItem, true, false); + boolean canEquip2 = target.maybeEquip(game, selItem, true, false); + + if (equipped1 || canEquip1) { + equip1Button.setText(equipped1 ? "Unequip" : "Equip"); + equip1Button.setEnabled(true); + } + if (equipped2 || canEquip2) { + equip2Button.setText(equipped2 ? "Unequip" : "Set Gun 2"); + equip2Button.setEnabled(true); + } + } + /** * Sets the ship whose inventory we're viewing. * @param solship The mercenary being interacted with diff --git a/engine/src/main/java/org/destinationsol/game/screens/TakeItems.java b/engine/src/main/java/org/destinationsol/game/screens/TakeItems.java index 00e32cd6f..639d1df3f 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/TakeItems.java +++ b/engine/src/main/java/org/destinationsol/game/screens/TakeItems.java @@ -16,24 +16,41 @@ package org.destinationsol.game.screens; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; import org.destinationsol.game.Hero; import org.destinationsol.game.SolGame; import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiControl; +import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; +/** + * This screen allows the hero to take items acquired by their hired mercenaries. + * The items taken will be transferred directly into the hero's inventory. + */ public class TakeItems extends InventoryOperationsScreen { - public final SolUiControl takeControl; + public final UIButton[] actionButtons = new UIButton[1]; private SolShip target; - TakeItems(InventoryScreen inventoryScreen, GameOptions gameOptions) { - takeControl = new SolUiControl(inventoryScreen.itemCtrl(0), true, gameOptions.getKeyShoot()); - takeControl.setDisplayName("Take"); - controls.add(takeControl); + public TakeItems() { + } + + @Override + public void initialise(SolApplication solApplication, InventoryScreen inventoryScreen) { + KeyActivatedButton takeButton = new KeyActivatedButton("takeButton", "Take"); + takeButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot())); + takeButton.subscribe(button -> { + SolItem selectedItem = inventoryScreen.getSelectedItem(); + Hero hero = solApplication.getGame().getHero(); + + target.getItemContainer().remove(selectedItem); + hero.getItemContainer().add(selectedItem); + inventoryScreen.updateItemRows(); + }); + actionButtons[0] = takeButton; } @Override @@ -47,24 +64,21 @@ public String getHeader() { } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { + public UIButton[] getActionButtons() { + return actionButtons; + } + + @Override + public void update(SolApplication solApplication, InventoryScreen inventoryScreen) { SolGame game = solApplication.getGame(); - InventoryScreen is = game.getScreens().inventoryScreen; Hero hero = game.getHero(); - - SolItem selItem = is.getSelectedItem(); - boolean enabled = selItem != null && hero.getItemContainer().canAdd(selItem); - takeControl.setDisplayName(enabled ? "Take" : "---"); - takeControl.setEnabled(enabled); - - if (!enabled) { - return; - } - - if (takeControl.isJustOff()) { - target.getItemContainer().remove(selItem); - hero.getItemContainer().add(selItem); - } + + UIButton takeButton = actionButtons[0]; + + SolItem selectedItem = inventoryScreen.getSelectedItem(); + boolean enabled = selectedItem != null && hero.getItemContainer().canAdd(selectedItem); + takeButton.setText(enabled ? "Take" : "---"); + takeButton.setEnabled(enabled); } /** diff --git a/engine/src/main/java/org/destinationsol/game/screens/TalkScreen.java b/engine/src/main/java/org/destinationsol/game/screens/TalkScreen.java index 5aa7e8b9b..f8fb1e29d 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/TalkScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/TalkScreen.java @@ -28,6 +28,7 @@ import org.destinationsol.ui.SolUiBaseScreen; import org.destinationsol.ui.SolUiControl; import org.destinationsol.ui.UiDrawer; +import org.destinationsol.ui.nui.screens.InventoryScreen; public class TalkScreen extends SolUiBaseScreen { public static final float MAX_TALK_DIST = 1f; @@ -88,10 +89,21 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi boolean buy = buyControl.isJustOff(); boolean sellShips = shipsControl.isJustOff(); boolean hire = hireControl.isJustOff(); - if (sell || buy || sellShips || hire) { - inventoryScreen.setOperations(sell ? inventoryScreen.sellItems : buy ? inventoryScreen.buyItemsScreen : sellShips ? inventoryScreen.changeShipScreen : inventoryScreen.hireShipsScreen); + InventoryOperationsScreen inventoryOperations = null; + if (buy) { + inventoryOperations = inventoryScreen.getBuyItemsScreen(); + } else if (sell) { + inventoryOperations = inventoryScreen.getSellItems(); + } else if (sellShips) { + inventoryOperations = inventoryScreen.getChangeShipScreen(); + } else if (hire) { + inventoryOperations = inventoryScreen.getHireShipsScreen(); + } + + if (inventoryOperations != null) { + inventoryScreen.setOperations(inventoryOperations); inputManager.setScreen(solApplication, game.getScreens().mainGameScreen); - inputManager.addScreen(solApplication, inventoryScreen); + solApplication.getNuiManager().pushScreen(inventoryScreen); } } diff --git a/engine/src/main/java/org/destinationsol/ui/TutorialManager.java b/engine/src/main/java/org/destinationsol/ui/TutorialManager.java index 49f114ad6..641523228 100644 --- a/engine/src/main/java/org/destinationsol/ui/TutorialManager.java +++ b/engine/src/main/java/org/destinationsol/ui/TutorialManager.java @@ -15,6 +15,8 @@ */ package org.destinationsol.ui; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.math.Rectangle; import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; @@ -23,12 +25,10 @@ import org.destinationsol.game.UpdateAwareSystem; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.screens.GameScreens; -import org.destinationsol.game.screens.InventoryScreen; import org.destinationsol.game.screens.MainGameScreen; import org.destinationsol.game.screens.ShipMixedControl; import org.destinationsol.ui.nui.screens.UIShipControlsScreen; import org.destinationsol.ui.nui.widgets.UIWarnButton; -import org.terasology.nui.widgets.UIButton; import java.util.ArrayList; import java.util.List; @@ -139,23 +139,22 @@ public void start() { } if (mouseCtrl || mobile) { - addStep("In the inventory,\nselect the second row", screens.inventoryScreen.itemControls[1]); + addStep("In the inventory,\nselect the second row", screens.inventoryScreen.getRowButton(1)); } else { - addStep("In the inventory,\nselect the next item (" + gameOptions.getKeyDownName() + " key)", - screens.inventoryScreen.downControl); + addStep("In the inventory,\nselect the next item (" + gameOptions.getKeyDownName() + " key)", gameOptions.getKeyDown()); } if (mouseCtrl || mobile) { - addStep("Go to the next page", screens.inventoryScreen.nextControl, true); + addStep("Go to the next page", screens.inventoryScreen.getNextButton(), true); } else { - addStep("Go to the next page\n(" + gameOptions.getKeyRightName() + " key)", screens.inventoryScreen.nextControl, true); + addStep("Go to the next page\n(" + gameOptions.getKeyRightName() + " key)", screens.inventoryScreen.getNextButton(), true); } if (mouseCtrl || mobile) { - addStep("Throw away some item\nyou don't use", screens.inventoryScreen.showInventory.dropControl); + addStep("Throw away some item\nyou don't use", screens.inventoryScreen.getShowInventory().getDropControl()); } else { addStep("Throw away some item\nyou don't use (" + gameOptions.getKeyDropName() + " key)", - screens.inventoryScreen.showInventory.dropControl); + screens.inventoryScreen.getShowInventory().getDropControl()); } // Extra step to make sure an equipped item is selected before asking player to unequip @@ -166,22 +165,22 @@ public void start() { } if (mobile) { - addStep("Unequip the item\nthat is used now", screens.inventoryScreen.showInventory.eq1Control); + addStep("Unequip the item\nthat is used now", screens.inventoryScreen.getShowInventory().getEq1Control()); } else { addStep("Unequip the item\nthat is used now (" + gameOptions.getKeyEquipName() + " key)", - screens.inventoryScreen.showInventory.eq1Control); + screens.inventoryScreen.getShowInventory().getEq1Control()); } if (mobile) { - addStep("Now equip it again", screens.inventoryScreen.showInventory.eq1Control); + addStep("Now equip it again", screens.inventoryScreen.getShowInventory().getEq1Control()); } else { - addStep("Now equip it again\n(" + gameOptions.getKeyEquipName() + " key)", screens.inventoryScreen.showInventory.eq1Control); + addStep("Now equip it again\n(" + gameOptions.getKeyEquipName() + " key)", screens.inventoryScreen.getShowInventory().getEq1Control()); } if (mobile) { - addStep("Close the inventory\n(Touch the screen outside inventory)", screens.inventoryScreen.closeControl, true); + addStep("Close the inventory\n(Touch the screen outside inventory)", screens.inventoryScreen.getCloseButton(), true); } else { - addStep("Close the inventory (" + gameOptions.getKeyCloseName() + " key)", screens.inventoryScreen.closeControl, true); + addStep("Close the inventory (" + gameOptions.getKeyCloseName() + " key)", screens.inventoryScreen.getCloseButton(), true); } if (mouseCtrl) { @@ -206,15 +205,15 @@ public void start() { } if (mobile) { - addStep("Buy some item", screens.inventoryScreen.buyItemsScreen.buyControl); + addStep("Buy some item", screens.inventoryScreen.getBuyItemsScreen().getBuyControl()); } else { - addStep("Buy some item\n(" + gameOptions.getKeyBuyItemName() + " key)", screens.inventoryScreen.buyItemsScreen.buyControl); + addStep("Buy some item\n(" + gameOptions.getKeyBuyItemName() + " key)", screens.inventoryScreen.getBuyItemsScreen().getBuyControl()); } if (mobile) { - addStep("Close the Buy screen\n(Touch the screen outside inventory)", screens.inventoryScreen.closeControl, true); + addStep("Close the Buy screen\n(Touch the screen outside inventory)", screens.inventoryScreen.getCloseButton(), true); } else { - addStep("Close the Buy screen\n(" + gameOptions.getKeyCloseName() + " key)", screens.inventoryScreen.closeControl, true); + addStep("Close the Buy screen\n(" + gameOptions.getKeyCloseName() + " key)", screens.inventoryScreen.getCloseButton(), true); } if (mouseCtrl) { @@ -253,6 +252,10 @@ private void addStep(String text, SolUiControl ctrl) { addStep(text, ctrl, false); } + private void addStep(String text, int key) { + steps.add(new KeyPressedStep(text, key)); + } + private void addStep(String text, UIWarnButton ctrl) { addStep(text, ctrl, false); } @@ -367,10 +370,10 @@ public boolean canProgressToNextStep() { } public static class SelectEquippedItemStep extends Step { - InventoryScreen inventoryScreen; + org.destinationsol.ui.nui.screens.InventoryScreen inventoryScreen; SolGame game; - public SelectEquippedItemStep(String text, InventoryScreen inventoryScreen, SolGame game) { + public SelectEquippedItemStep(String text, org.destinationsol.ui.nui.screens.InventoryScreen inventoryScreen, SolGame game) { super(text, null, true); this.inventoryScreen = inventoryScreen; this.game = game; @@ -388,10 +391,24 @@ public boolean canProgressToNextStep() { // Highlight all equipped items on opened inventory page @Override public void highlight() { - List equippedItemControls = inventoryScreen.getEquippedItemUIControlsForTutorial(game); - for (SolUiControl control : equippedItemControls) { + List equippedItemControls = inventoryScreen.getEquippedItemUIControlsForTutorial(); + for (UIWarnButton control : equippedItemControls) { control.enableWarn(); } } } + + public static class KeyPressedStep extends Step { + private final int key; + + public KeyPressedStep(String text, int key) { + super(text, null, false); + this.key = key; + } + + @Override + public boolean canProgressToNextStep() { + return Gdx.input.isKeyJustPressed(key); + } + } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java index 669c2702d..d5aa4c8fb 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java @@ -184,6 +184,8 @@ public NUIManager(SolApplication solApplication, Context context, CommonDrawer c * @param solApplication the application to use */ public void update(SolApplication solApplication) { + mouse.update(); + for (int pointer = 0; pointer < mouse.getMaxPointers(); pointer++) { canvas.processMousePosition(mouse.getPosition(pointer), pointer); } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java index 84223b44e..39f32e4a0 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java @@ -122,15 +122,19 @@ public Iterator iterator() { */ @Override public boolean onKeyEvent(NUIKeyEvent event) { - if (escapeCloses() && event.getState() == ButtonState.UP && event.getKey() == Keyboard.Key.ESCAPE) { - nuiManager.removeScreen(this); - return true; - } - // Send key events to all KeyActivatedButton sub-widgets. These buttons are supposed to react to key events // even when they are not in-focus. for (UIWidget widget : contents.findAll(KeyActivatedButton.class)) { - widget.onKeyEvent(event); + if (widget.onKeyEvent(event)) { + return true; + } + } + + // Process escape key handling after KeyActivatedButton key events, since some screens might implement + // a close button bound to the escape key. + if (escapeCloses() && event.getState() == ButtonState.UP && event.getKey() == Keyboard.Key.ESCAPE) { + nuiManager.removeScreen(this); + return true; } return super.onKeyEvent(event); diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java new file mode 100644 index 000000000..868bcf477 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java @@ -0,0 +1,579 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.ui.nui.screens; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import org.destinationsol.Const; +import org.destinationsol.SolApplication; +import org.destinationsol.assets.Assets; +import org.destinationsol.common.In; +import org.destinationsol.game.item.ItemContainer; +import org.destinationsol.game.item.SolItem; +import org.destinationsol.game.screens.BuyItemsScreen; +import org.destinationsol.game.screens.ChangeShipScreen; +import org.destinationsol.game.screens.ChooseMercenaryScreen; +import org.destinationsol.game.screens.GameScreens; +import org.destinationsol.game.screens.GiveItemsScreen; +import org.destinationsol.game.screens.HireShipsScreen; +import org.destinationsol.game.screens.InventoryOperationsScreen; +import org.destinationsol.game.screens.SellItems; +import org.destinationsol.game.screens.ShowInventory; +import org.destinationsol.game.screens.TakeItems; +import org.destinationsol.ui.SolInputManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.UIWarnButton; +import org.terasology.nui.Color; +import org.terasology.nui.HorizontalAlign; +import org.terasology.nui.UIWidget; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.backends.libgdx.GdxColorUtil; +import org.terasology.nui.backends.libgdx.LibGDXTexture; +import org.terasology.nui.events.NUIKeyEvent; +import org.terasology.nui.layouts.ColumnLayout; +import org.terasology.nui.layouts.ScrollableArea; +import org.terasology.nui.layouts.relative.HorizontalHint; +import org.terasology.nui.layouts.relative.RelativeLayout; +import org.terasology.nui.layouts.relative.RelativeLayoutHint; +import org.terasology.nui.layouts.relative.VerticalHint; +import org.terasology.nui.widgets.UIButton; +import org.terasology.nui.widgets.UIImage; +import org.terasology.nui.widgets.UILabel; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * The Inventory screen displays a paginate-able list of {@link SolItem} that you can select and view information on. + * Specialised functionality and logic for the screen is implemented via an assigned {@link InventoryOperationsScreen}, + * which can provide up to 3 additional "action buttons" placed in the bottom-right corner of the screen. + */ +public class InventoryScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + private UILabel titleLabel; + private ColumnLayout inventoryRows; + private UIWarnButton nextButton; + private UIWarnButton previousButton; + private ScrollableArea descriptionScrollArea; + private UILabel descriptionBox; + private ColumnLayout inventoryActionButtons; + private UIWarnButton closeButton; + private InventoryOperationsScreen inventoryOperations; + private int selectedIndex; + private int page; + + private ShowInventory showInventory; + private BuyItemsScreen buyItemsScreen; + private SellItems sellItems; + private ChangeShipScreen changeShipScreen; + private HireShipsScreen hireShipsScreen; + // The below screens deal with mercenaries + private ChooseMercenaryScreen chooseMercenaryScreen; + private GiveItemsScreen giveItemsScreen; + private TakeItems takeItems; + + @Override + public void initialise() { + titleLabel = find("title", UILabel.class); + + inventoryRows = find("inventoryRows", ColumnLayout.class); + + nextButton = find("nextButton", UIWarnButton.class); + nextButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyRight())); + nextButton.subscribe(button -> { + nextPage(button); + selectedIndex = 0; + updateItemRows(); + }); + + previousButton = find("previousButton", UIWarnButton.class); + previousButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyLeft())); + previousButton.subscribe(button -> { + previousPage(button); + selectedIndex = 0; + updateItemRows(); + }); + + for (int rowNo = 0; rowNo < Const.ITEM_GROUPS_PER_PAGE; rowNo++) { + inventoryRows.addWidget(createItemRow(rowNo)); + } + + descriptionScrollArea = find("itemDescriptionScrollArea", ScrollableArea.class); + descriptionBox = find("itemDescription", UILabel.class); + + inventoryActionButtons = find("inventoryActionButtons", ColumnLayout.class); + + closeButton = new UIWarnButton("cancelButton", "Cancel"); + closeButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + closeButton.subscribe(button -> { + // Go back to the "Choose Mercenaries" screen if it was probably the last one opened. + if (inventoryOperations == giveItemsScreen || inventoryOperations == takeItems || + (inventoryOperations == showInventory && showInventory.getTarget() != solApplication.getGame().getHero().getShip())) { + SolInputManager inputMan = solApplication.getInputManager(); + GameScreens screens = solApplication.getGame().getScreens(); + + inputMan.setScreen(solApplication, screens.mainGameScreen); + onRemoved(); + setOperations(chooseMercenaryScreen); + onAdded(); + } else { + nuiManager.removeScreen(this); + } + }); + + showInventory = new ShowInventory(); + showInventory.initialise(solApplication, this); + buyItemsScreen = new BuyItemsScreen(); + buyItemsScreen.initialise(solApplication, this); + sellItems = new SellItems(); + sellItems.initialise(solApplication, this); + changeShipScreen = new ChangeShipScreen(); + changeShipScreen.initialise(solApplication, this); + hireShipsScreen = new HireShipsScreen(); + hireShipsScreen.initialise(solApplication, this); + chooseMercenaryScreen = new ChooseMercenaryScreen(); + chooseMercenaryScreen.initialise(solApplication, this); + giveItemsScreen = new GiveItemsScreen(); + giveItemsScreen.initialise(solApplication, this); + takeItems = new TakeItems(); + takeItems.initialise(solApplication, this); + } + + @Override + public void onAdded() { + titleLabel.setText(inventoryOperations.getHeader()); + descriptionBox.setText(""); + + selectedIndex = 0; + page = 0; + inventoryOperations.onAdd(solApplication); + + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + nextButton.setEnabled(Const.ITEM_GROUPS_PER_PAGE < items.groupCount()); + previousButton.setEnabled(false); + + for (UIButton actionButton : inventoryOperations.getActionButtons()) { + inventoryActionButtons.addWidget(actionButton); + } + + inventoryActionButtons.addWidget(closeButton); + + updateItemRows(); + } + + /** + * Assigns the specified {@link InventoryOperationsScreen operations screen} to this screen. + * @param operations the operations that can be performed + */ + public void setOperations(InventoryOperationsScreen operations) { + this.inventoryOperations = operations; + } + + @Override + public void update(float delta) { + super.update(delta); + + if (solApplication.getGame().getHero().getShip() == showInventory.getTarget() || inventoryOperations == sellItems) { + int itemNo = page * Const.ITEM_GROUPS_PER_PAGE; + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + Iterator rowIterator = inventoryRows.iterator(); + rowIterator.next(); // Skip header + while (rowIterator.hasNext()) { + UIWidget row = rowIterator.next(); + if (itemNo >= items.groupCount()) { + break; + } + + UIWarnButton itemButton = row.find("itemButton", UIWarnButton.class); + if (itemButton != null && !itemButton.isWarning() && items.isNew(items.getGroup(itemNo))) { + itemButton.enableWarn(); + } + itemNo++; + } + } + + inventoryOperations.update(solApplication, this); + } + + @Override + public void onRemoved() { + super.onRemoved(); + + if (inventoryOperations != null) { + inventoryOperations.getItems(solApplication.getGame()).markAllAsSeen(); + inventoryActionButtons.removeAllWidgets(); + } + } + + @Override + public boolean onKeyEvent(NUIKeyEvent event) { + if (super.onKeyEvent(event)) { + return true; + } + + if (event.isDown()) { + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + if (event.getKey() == GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyUp())) { + if (selectedIndex < 1 && previousButton.isEnabled()) { + selectedIndex = Const.ITEM_GROUPS_PER_PAGE - 1; + previousPage(previousButton); + previousButton.getClickSound().play(previousButton.getClickVolume()); + } else if (selectedIndex > 0) { + selectedIndex--; + previousButton.getClickSound().play(previousButton.getClickVolume()); + } + + items.seen(items.getGroup(selectedIndex + page * Const.ITEM_GROUPS_PER_PAGE)); + + updateItemRows(); + return true; + } + + if (event.getKey() == GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyDown())) { + int itemsMaxIndex = items.groupCount() - 1; + int maxIndex = Math.min(Const.ITEM_GROUPS_PER_PAGE - 1, itemsMaxIndex - (page * Const.ITEM_GROUPS_PER_PAGE)); + if (selectedIndex >= maxIndex && nextButton.isEnabled()) { + selectedIndex = 0; + nextPage(nextButton); + nextButton.getClickSound().play(nextButton.getClickVolume()); + } else if (selectedIndex < maxIndex) { + selectedIndex++; + nextButton.getClickSound().play(nextButton.getClickVolume()); + } + + items.seen(items.getGroup(selectedIndex + page * Const.ITEM_GROUPS_PER_PAGE)); + + updateItemRows(); + return true; + } + } + + return false; + } + + /** + * Returns the currently selected item group. + * @return the selected item group + */ + public List getSelected() { + if (inventoryOperations == null || selectedIndex < 0 || selectedIndex >= Const.ITEM_GROUPS_PER_PAGE) { + return null; + } + + int itemGroupIndex = selectedIndex + page * Const.ITEM_GROUPS_PER_PAGE; + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + if (itemGroupIndex >= items.groupCount()) { + return null; + } + + return items.getGroup(itemGroupIndex); + } + + /** + * Retrieves the currently selected item. + * @return the current selected item + */ + public SolItem getSelectedItem() { + List itemGroup = getSelected(); + if (itemGroup == null) { + return null; + } + return itemGroup.isEmpty() ? null : itemGroup.get(0); + } + + /** + * Sets the selected item group. + * @param itemGroup the item group to select + */ + public void setSelected(List itemGroup) { + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + if (!items.containsGroup(itemGroup)) { + selectedIndex = 0; + return; + } + + for (int groupNo = 0; groupNo < items.groupCount(); groupNo++) { + if (items.getGroup(groupNo) == itemGroup) { + page = groupNo / Const.ITEM_GROUPS_PER_PAGE; + selectedIndex = groupNo % Const.ITEM_GROUPS_PER_PAGE; + } + } + + updateItemRows(); + } + + /** + * Returns the button representing the specified row. + * @param index the row to retrieve + * @return the row's item button + */ + public UIWarnButton getRowButton(int index) { + Iterator rowIterator = inventoryRows.iterator(); + rowIterator.next(); // Skip header + for (int rowNo = 0; rowNo < index; rowNo++) { + rowIterator.next(); + } + return rowIterator.next().find("itemButton", UIWarnButton.class); + } + + /** + * This is an internal API used by the tutorial. It just returns the buttons representing equipped items. + * @return The buttons representing currently equipped items. + */ + public List getEquippedItemUIControlsForTutorial() { + List controls = new ArrayList<>(); + + Iterator rowsIterator = inventoryRows.iterator(); + rowsIterator.next(); // Skip header + UIWidget row = rowsIterator.next(); + int startIndex = page * Const.ITEM_GROUPS_PER_PAGE; + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + for (int rowNo = 0; rowNo < Const.ITEM_GROUPS_PER_PAGE; rowNo++) { + int groupNo = startIndex + rowNo; + boolean emptyRow = groupNo >= items.groupCount(); + + UIWarnButton itemButton = row.find("itemButton", UIWarnButton.class); + if (emptyRow) { + break; + } else { + List itemGroup = items.getGroup(groupNo); + SolItem sample = itemGroup.get(0); + + if (inventoryOperations.isUsing(solApplication.getGame(), sample)) { + controls.add(itemButton); + } + } + + if (rowsIterator.hasNext()) { + row = rowsIterator.next(); + } + } + + return controls; + } + + /** + * @return the next button - used in the tutorial + */ + public UIWarnButton getNextButton() { + return nextButton; + } + + /** + * @return the previous button + */ + public UIWarnButton getPreviousButton() { + return previousButton; + } + + /** + * @return the close button - used in the tutorial + */ + public UIWarnButton getCloseButton() { + return closeButton; + } + + /** + * @return the {@link ShowInventory} inventory operations + */ + public ShowInventory getShowInventory() { + return showInventory; + } + + /** + * @return the {@link BuyItemsScreen} inventory operations + */ + public BuyItemsScreen getBuyItemsScreen() { + return buyItemsScreen; + } + + /** + * @return the {@link SellItems} inventory operations + */ + public SellItems getSellItems() { + return sellItems; + } + + /** + * @return the {@link ChangeShipScreen} inventory operations + */ + public ChangeShipScreen getChangeShipScreen() { + return changeShipScreen; + } + + /** + * @return the {@link HireShipsScreen} inventory operations + */ + public HireShipsScreen getHireShipsScreen() { + return hireShipsScreen; + } + + /** + * @return the {@link ChooseMercenaryScreen} inventory operations + */ + public ChooseMercenaryScreen getChooseMercenaryScreen() { + return chooseMercenaryScreen; + } + + /** + * @return the {@link GiveItemsScreen} inventory operations + */ + public GiveItemsScreen getGiveItems() { + return giveItemsScreen; + } + + /** + * @return the {@link TakeItems} inventory operations + */ + public TakeItems getTakeItems() { + return takeItems; + } + + private UIWidget createItemRow(int index) { + RelativeLayout itemRowLayout = new RelativeLayout(); + itemRowLayout.setFamily("inventoryRow"); + + UIWarnButton itemButton = new UIWarnButton("itemButton", ""); + itemButton.subscribe(button -> { + selectedIndex = index; + updateItemRows(); + }); + itemRowLayout.addWidget(itemButton, new RelativeLayoutHint()); + + UIImage itemIconBackground = new UIImage("itemIconBackground", Assets.getDSTexture("engine:whiteTex").getUiTexture()); + itemRowLayout.addWidget(itemIconBackground, new RelativeLayoutHint( + new HorizontalHint() + .alignLeftRelativeTo("itemIcon", HorizontalAlign.LEFT) + .alignRightRelativeTo("itemIcon", HorizontalAlign.RIGHT), + new VerticalHint() + )); + + UIImage itemIcon = new UIImage("itemIcon"); + itemRowLayout.addWidget(itemIcon, new RelativeLayoutHint( + new HorizontalHint().alignLeft(8), + new VerticalHint() + ).setUsingContentWidth(true)); + + itemRowLayout.addWidget(new UILabel("itemEquippedLabel", ""), new RelativeLayoutHint( + new HorizontalHint().alignLeftRelativeTo("itemIcon", HorizontalAlign.RIGHT, 8), + new VerticalHint() + ).setUsingContentWidth(true)); + + itemRowLayout.addWidget(new UILabel("itemQuantityLabel", ""), new RelativeLayoutHint( + new HorizontalHint().alignRight(8), + new VerticalHint() + ).setUsingContentWidth(true)); + + itemRowLayout.addWidget(new UILabel("itemPriceLabel", ""), new RelativeLayoutHint( + new HorizontalHint().alignRight(64), + new VerticalHint() + ).setUsingContentWidth(true)); + + return itemRowLayout; + } + + public void updateItemRows() { + ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); + Iterator rowsIterator = inventoryRows.iterator(); + rowsIterator.next(); // Ignore the first row, since it's the header. + UIWidget row = rowsIterator.next(); + + int startIndex = page * Const.ITEM_GROUPS_PER_PAGE; + if (startIndex >= items.groupCount() && page > 0) { + // Empty page. This may have happened if the last item on a page was dropped from the inventory. + page = (items.groupCount() - 1) / Const.ITEM_GROUPS_PER_PAGE; + startIndex = page * Const.ITEM_GROUPS_PER_PAGE; + selectedIndex = 0; + } + + previousButton.setEnabled(page > 0); + nextButton.setEnabled(((page + 1) * Const.ITEM_GROUPS_PER_PAGE) < items.groupCount()); + + for (int rowNo = 0; rowNo < Const.ITEM_GROUPS_PER_PAGE; rowNo++) { + int groupNo = startIndex + rowNo; + boolean emptyRow = groupNo >= items.groupCount(); + + UIWarnButton itemButton = row.find("itemButton", UIWarnButton.class); + UIImage itemIconBackground = row.find("itemIconBackground", UIImage.class); + UIImage itemIcon = row.find("itemIcon", UIImage.class); + UILabel itemEquippedLabel = row.find("itemEquippedLabel", UILabel.class); + UILabel itemQuantityLabel = row.find("itemQuantityLabel", UILabel.class); + UILabel itemPriceLabel = row.find("itemPriceLabel", UILabel.class); + if (emptyRow) { + itemButton.setText(""); + itemIconBackground.setTint(new Color(Color.transparent)); + itemIcon.setImage(null); + itemEquippedLabel.setText(""); + itemQuantityLabel.setText(""); + itemPriceLabel.setText(""); + + itemButton.setEnabled(false); + } else { + List itemGroup = items.getGroup(groupNo); + SolItem sample = itemGroup.get(0); + + itemButton.setText(sample.getDisplayName()); + itemButton.setActive(selectedIndex == rowNo); + if (items.isNew(itemGroup)) { + itemButton.enableWarn(); + } + + itemIconBackground.setTint(GdxColorUtil.gdxToTerasologyColor(sample.getItemType().uiColor)); + + TextureAtlas.AtlasRegion iconTexture = sample.getIcon(solApplication.getGame()); + itemIcon.setImage(new LibGDXTexture(iconTexture)); + + itemEquippedLabel.setText(inventoryOperations.isUsing(solApplication.getGame(), sample) ? "using" : ""); + + itemQuantityLabel.setText(itemGroup.size() > 1 ? "x" + itemGroup.size() : ""); + + itemPriceLabel.setText(inventoryOperations.getPriceMul() > 0 ? "$" + sample.getPrice() * inventoryOperations.getPriceMul() : ""); + + itemButton.setEnabled(true); + } + + if (rowsIterator.hasNext()) { + row = rowsIterator.next(); + } + } + + int selectedGroup = (selectedIndex + page * Const.ITEM_GROUPS_PER_PAGE); + if (items.groupCount() > 0 && items.groupCount() > selectedGroup) { + List itemGroup = items.getGroup(selectedGroup); + items.seen(itemGroup); + SolItem sample = itemGroup.get(0); + // Add an extra newline to the end to ensure that the entire area is scrollable. + descriptionBox.setText(sample.getDisplayName() + "\n" + sample.getDescription() + "\n"); + // Scroll to top + descriptionScrollArea.setPosition(0); + } + } + + private void nextPage(UIWidget nextButton) { + int inputCount = inventoryOperations.getItems(solApplication.getGame()).groupCount(); + page++; + nextButton.setEnabled(((page + 1) * Const.ITEM_GROUPS_PER_PAGE) < inputCount); + previousButton.setEnabled(true); + } + + private void previousPage(UIWidget previousButton) { + page--; + previousButton.setEnabled(page > 0); + nextButton.setEnabled(true); + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index b72049d1d..189942482 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -109,7 +109,7 @@ public void update(float delta) { SolGame game = solApplication.getGame(); Hero hero = game.getHero(); - if (hero.isNonTranscendent() && !solInputManager.isScreenOn(gameScreens.inventoryScreen)) { + if (hero.isNonTranscendent() && !nuiManager.hasScreen(gameScreens.inventoryScreen)) { if (hero.getItemContainer().hasNew()) { inventoryButton.enableWarn(); } @@ -256,10 +256,12 @@ private void onItemsButtonClicked(UIWidget widget) { GameScreens gameScreens = solApplication.getGame().getScreens(); solInputManager.setScreen(solApplication, gameScreens.mainGameScreen); - if (!solInputManager.isScreenOn(gameScreens.inventoryScreen)) { - gameScreens.inventoryScreen.showInventory.setTarget(solApplication.getGame().getHero().getShip()); - gameScreens.inventoryScreen.setOperations(gameScreens.inventoryScreen.showInventory); - solInputManager.addScreen(solApplication, gameScreens.inventoryScreen); + if (!nuiManager.hasScreen(gameScreens.inventoryScreen)) { + gameScreens.inventoryScreen.getShowInventory().setTarget(solApplication.getGame().getHero().getShip()); + gameScreens.inventoryScreen.setOperations(gameScreens.inventoryScreen.getShowInventory()); + nuiManager.pushScreen(gameScreens.inventoryScreen); + } else { + nuiManager.removeScreen(gameScreens.inventoryScreen); } } @@ -279,9 +281,9 @@ private void onMercsButtonClicked(UIWidget widget) { GameScreens gameScreens = solApplication.getGame().getScreens(); solInputManager.setScreen(solApplication, gameScreens.mainGameScreen); - if (!solInputManager.isScreenOn(gameScreens.inventoryScreen)) { - gameScreens.inventoryScreen.setOperations(gameScreens.inventoryScreen.chooseMercenaryScreen); - solInputManager.addScreen(solApplication, gameScreens.inventoryScreen); + if (!nuiManager.hasScreen(gameScreens.inventoryScreen)) { + gameScreens.inventoryScreen.setOperations(gameScreens.inventoryScreen.getChooseMercenaryScreen()); + nuiManager.pushScreen(gameScreens.inventoryScreen); solApplication.getGame().getHero().getMercs().markAllAsSeen(); } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/widgets/KeyActivatedButton.java b/engine/src/main/java/org/destinationsol/ui/nui/widgets/KeyActivatedButton.java index 539956cea..5b32e58a2 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/widgets/KeyActivatedButton.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/widgets/KeyActivatedButton.java @@ -42,6 +42,17 @@ public class KeyActivatedButton extends UIButton { @LayoutConfig private Binding activateWhenInvisible = new DefaultBinding<>(false); + public KeyActivatedButton(){ + } + + public KeyActivatedButton(String id) { + super(id); + } + + public KeyActivatedButton(String id, String text) { + super(id, text); + } + /** * Binds the key used to activate this {@code KeyActivatedButton}. * @@ -104,6 +115,11 @@ public boolean onKeyEvent(NUIKeyEvent event) { return true; } + // WidgetWithOrder contains some logic that consumed all UP key and DOWN key events, even when it does nothing + // with them. This might be worthwhile for scrolling lists but shouldn't do anything otherwise. + if (parent == null) { + return false; + } return super.onKeyEvent(event); } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIWarnButton.java b/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIWarnButton.java index 24b4c900c..5d9cf2af5 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIWarnButton.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIWarnButton.java @@ -38,6 +38,17 @@ public class UIWarnButton extends KeyActivatedButton { private boolean warnPercGrows; private float warnAlpha = 1f; + public UIWarnButton() { + } + + public UIWarnButton(String id) { + super(id); + } + + public UIWarnButton(String id, String text) { + super(id, text); + } + @Override public void onDraw(Canvas canvas) { if (warnCounter > 0) { @@ -80,6 +91,14 @@ public void enableWarn() { warnCounter = WARN_COUNTER_MAX; } + /** + * Returns true if the button is currently in a "warn" phase. + * @return true, if the button is currently in a "warn" phase, otherwise false. + */ + public boolean isWarning() { + return warnCounter > 0; + } + @Override public boolean isSkinAppliedByCanvas() { return false; diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/inventoryScreen.skin b/engine/src/main/resources/org/destinationsol/assets/skins/inventoryScreen.skin new file mode 100644 index 000000000..aed32aa82 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/skins/inventoryScreen.skin @@ -0,0 +1,24 @@ +{ + "inherit": "engine:mainGameScreen", + "families": { + "inventoryHeader": { + "text-align-vertical": "middle", + "text-align-horizontal": "left", + "min-height": 16 + }, + "inventoryRow": { + "font": "engine:main#0.675", + "text-align-vertical": "middle", + "text-align-horizontal": "center", + "min-height": 32, + "max-height": 64 + }, + "inventoryActionButtons": { + "font": "engine:main#0.4" + }, + "selectedItemLabel": { + "text-align-vertical": "middle", + "text-align-horizontal": "left" + } + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin index b3b4d1619..1cbc58ccd 100644 --- a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin +++ b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin @@ -12,6 +12,22 @@ }, "controlsUIButton": { "font": "engine:main#0.95" + }, + "menuBox": { + "max-width": 800, + "max-height": 600, + "elements": { + "UIBox": { + "background": "engine:background" + } + } + }, + "uiBoxDefault": { + "elements": { + "UIBox": { + "background": "engine:area" + } + } } } } diff --git a/engine/src/main/resources/org/destinationsol/assets/textures/ui/nui/background.png b/engine/src/main/resources/org/destinationsol/assets/textures/ui/nui/background.png new file mode 100644 index 0000000000000000000000000000000000000000..5e7f2df6986b940b3f0ccf935c8a050142a99606 GIT binary patch literal 4881 zcmeHLdsGu=79UV~39eKHDsnbPERQlwGI@|hf;@#F0Sf3M$bm^RfswpO1`{dB(?gN^ zK(T_Ni&BdUNY$k(EGv|9XnE9krJzFDrSi~9YL8l9-7f(V&-NeBZqNS1SBMR!glQ2(l4`1V(}H9K&s42A*v`SQiADPGrQyl2MqJqEaiRgbb&U zTU0m&*AY?(()Hcn|G}PdSL>kPHne-R?pgRwS8LMAI}4=0YPLB=xEy+Xg^^hA9%)9M z2pWL|SM`tU%U}8*9b1XBkcLtlx0@R;9QmQYyw9EJs@XVtW!t5QN2Hb(mKS%*zLWJ5 ztBxP6T^jdv-SI@HXPV%i{r|XVq2D0TExw;-d1GzJlY5nGD-U(`g{D7iEO@~g*T)w9 zHDWvU+1dU9AIGC!iyvA%T<+``YPZ^Hx6V~iyr6Vs5Rdz$(Ic~HIpx6+S#7mTdj7z` zf{df;b0f|C=Bu5VHYNKh`3%mj zH|61~^%KS1JR7gPjinA|RAznUnAOCJi=Pd;Q;ypXbEr#lZ$}g*j1C<1wM%LB4az#~ zcP7n}5?B`ZgSDka&eEc&BRyq1EOJR`lj_jQhYL(U?VJ;?wsT9$-&=4(zx~S6&Q6+3 zZ(4b7L8$E<#|pHibHnLuk5!K%qp#GS3=$^Pd_i4l4C&en^|| zvi8L2Ah&%BqzgxPAK`77n4ebaZrAEhy#KecB=w7e_iO~)i>n6XR1@OUV}nDrHTg9Z zi>*25FL2!&LyCS|YXytEIX`tYeYmShn{&Aqy>ahd^OznqN?%smQx}?5Z$YuPT^{yz z_w_}i?bhBMH~E>F&BZ@^JkVtC%*||-T2~DUa>F+zb>zQfJ^_xl&Ny4|9J43bW$7{19UVfS6 z7cbBpk~*Y$EYEdzc0FE|=k5_m+z6qU9DPw%nBA*)`R3T}8q+m9=UuP#-~4p2_n|E&IOH-#pNA&t-JSPCKrte}7ARdT{ik zoGz!N5y5_&?@OLDw~1_ZtE-fqCi&-llX~vgHSfA+P6 z;vtAutM$|}JeBHXgwEx15gLl1C=4`U%@zfT>0pIsg#ls`BM{e!)r5*9lnROg6B8-Z zNj{Yd<|(h@ldFWnX?TTZiUq(2qQg`O-IIpM<;YA64H>iYR3>F9@r!5Q=BolI#(F&0Lh9*f! zUz7DlY=#+QIx_-@vrsP%%w*CeForWw z7{f4}>xHp#CWmf>l8AY0lxjH!mXnZU$vC1?BpW9Tg!B9&1$-*%IqB6XiIica6c~U# zKqw?it>(3I3?av(NzA|}oy}k|Stx^zqFfGxJL$@3zaCd>KrI?j=`>H2V>CA`3=gCO zsKpGG3IL39kPREnSyLU2^q7YxK5Gj_NKlz1vfB7L+LP` z2HeD;bRM0{Ls2R+l`LY|)337iM*f2jZ==GDCIIXvWuUo$UWH6It0}$=6#jwN)H?iu z9su;Llegk`mabX4-im>@Ql71@S-Reefwxkgt*-wWT~@D;JGcV;0@8xRj9us4GvFX( zCR!UD2>oXGR5n-d1rkeD$Oa7r&0l1=O`ro64nSy53WP!C!&b`{FS3haBRU}ZNf784 z1OC#vYGMOH7HyyBXGg@gnOW8q;QJ(B#>2TLG{~$4a)9O}LDo6{&p`|H&VL=nt" + } + ] + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "offset": 8 + }, + "position-bottom": { + "widget": "selectedItemLabel", + "target": "TOP", + "offset": 8 + }, + "position-left": { + "offset": 8 + }, + "position-right": { + "offset": 8 + } + } + }, + { + "type": "UILabel", + "id": "selectedItemLabel", + "text": "Selected Item:", + "layoutInfo": { + "position-top": { + "target": "MIDDLE", + "offset": 64 + }, + "position-left": { + "offset": 8 + }, + "position-right": { + "offset": 8 + }, + "use-content-height": true + } + }, + { + "type": "RowLayout", + "id": "inventoryItemInfo", + "horizontalSpacing": 16, + "contents": [ + { + "type": "UIBox", + "id": "itemDescriptionBox", + "family": "uiBoxDefault", + "content": { + "type": "ScrollableArea", + "id": "itemDescriptionScrollArea", + "content": { + "type": "UILabel", + "id": "itemDescription", + "text": "This is a really long description. Longer than that. No, even longer!" + } + }, + "layoutInfo": { + "relativeWidth": 0.6 + } + }, + { + "type": "ColumnLayout", + "id": "inventoryActionButtons", + "family": "inputMapOptions", + "verticalSpacing": 8, + "contents": [ + ] + } + ], + "layoutInfo": { + "position-top": { + "widget": "selectedItemLabel", + "target": "BOTTOM", + "offset": 8 + }, + "position-bottom": { + "offset": 8 + }, + "position-left": { + "offset": 8 + }, + "position-right": { + "offset": 8 + } + } + } + ] + }, + "layoutInfo": { + "position-horizontal-center": {}, + "position-vertical-center": {}, + "position-top": { + "offset": 64 + }, + "position-bottom": { + "offset": 64 + }, + "position-left": { + "offset": 64 + }, + "position-right": { + "offset": 64 + } + } + } + ] + } +} \ No newline at end of file From ddbd863b343cf0372514cfa7e7ccf0b1e7519c7e Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Wed, 10 Nov 2021 20:37:19 +0000 Subject: [PATCH 2/5] feat(nui): remove screens when clicking outside of their area --- .../game/screens/MainGameScreen.java | 5 +- .../org/destinationsol/ui/nui/NUIManager.java | 2 +- .../ui/nui/screens/MainGameScreen.java | 22 +++++++++ .../ui/nui/widgets/UIBackingBox.java | 48 +++++++++++++++++++ .../assets/ui/inventoryScreen.ui | 2 +- 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 engine/src/main/java/org/destinationsol/ui/nui/widgets/UIBackingBox.java diff --git a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java index f725a33c1..f662a82a8 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java @@ -48,6 +48,7 @@ import org.destinationsol.ui.SolUiControl; import org.destinationsol.ui.SolUiScreen; import org.destinationsol.ui.UiDrawer; +import org.destinationsol.ui.nui.NUIScreenLayer; import org.destinationsol.ui.nui.screens.ConsoleScreen; import org.destinationsol.ui.nui.screens.UIShipControlsScreen; import org.terasology.gestalt.assets.ResourceUrn; @@ -225,7 +226,9 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi zoneNameAnnouncer.update(game, context); - boolean controlsEnabled = inputMan.getTopScreen() == this; + NUIScreenLayer topScreen = solApplication.getNuiManager().getTopScreen(); + boolean controlsEnabled = inputMan.getTopScreen() == this && + (topScreen instanceof org.destinationsol.ui.nui.screens.MainGameScreen || topScreen instanceof UIShipControlsScreen); shipControl.update(solApplication, controlsEnabled); SolCam.DIRECT_CAM_CONTROL = freeCamControl.isOn(); diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java index d5aa4c8fb..b9d33d526 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java @@ -436,7 +436,7 @@ public boolean isMouseOnUi() { // TODO: Find better way of doing this. Vector2i mousePosition = mouse.getPosition(); for (Rectanglei interactionRegion : canvas.getInteractionRegions()) { - if (RectUtility.contains(interactionRegion, mousePosition)) { + if (!interactionRegion.equals(canvas.getRegion()) && interactionRegion.containsPoint(mousePosition)) { return true; } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index 189942482..a8b31260c 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -34,10 +34,14 @@ import org.terasology.input.ButtonState; import org.terasology.input.Keyboard; import org.terasology.nui.AbstractWidget; +import org.terasology.nui.BaseInteractionListener; +import org.terasology.nui.Canvas; +import org.terasology.nui.InteractionListener; import org.terasology.nui.UIWidget; import org.terasology.nui.asset.UIElement; import org.terasology.nui.backends.libgdx.GDXInputUtil; import org.terasology.nui.events.NUIKeyEvent; +import org.terasology.nui.events.NUIMouseClickEvent; import java.util.List; @@ -58,6 +62,18 @@ public class MainGameScreen extends NUIScreenLayer { @In private SolApplication solApplication; + private final InteractionListener interactionListener = new BaseInteractionListener() { + @Override + public boolean onMouseClick(NUIMouseClickEvent event) { + NUIScreenLayer topScreen = nuiManager.getTopScreen(); + if (topScreen != MainGameScreen.this && !(topScreen instanceof UIShipControlsScreen)) { + nuiManager.popScreen(); + return true; + } + return false; + } + }; + @Override public void initialise() { consoleScreen = (ConsoleScreen) nuiManager.createScreen("engine:console"); @@ -158,6 +174,12 @@ public void update(float delta) { } } + @Override + public void onDraw(Canvas canvas) { + canvas.addInteractionRegion(interactionListener); + super.onDraw(canvas); + } + @Override protected boolean escapeCloses() { return false; diff --git a/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIBackingBox.java b/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIBackingBox.java new file mode 100644 index 000000000..66efd1291 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/widgets/UIBackingBox.java @@ -0,0 +1,48 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.ui.nui.widgets; + +import org.terasology.nui.BaseInteractionListener; +import org.terasology.nui.Canvas; +import org.terasology.nui.InteractionListener; +import org.terasology.nui.events.NUIMouseClickEvent; +import org.terasology.nui.events.NUIMouseDoubleClickEvent; +import org.terasology.nui.widgets.UIBox; + +/** + * A {@link UIBox} that is designed to back an existing group of widgets, acting effectively as the background + * but absorbing all click and double-click events to prevent event propagation to the screens behind it. + */ +public class UIBackingBox extends UIBox { + private static final InteractionListener BLOCKING_INTERACTION_LISTENER = new BaseInteractionListener() { + @Override + public boolean onMouseClick(NUIMouseClickEvent event) { + return true; + } + + @Override + public boolean onMouseDoubleClick(NUIMouseDoubleClickEvent event) { + return true; + } + }; + + @Override + public void onDraw(Canvas canvas) { + canvas.addInteractionRegion(BLOCKING_INTERACTION_LISTENER); + super.onDraw(canvas); + } +} diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/inventoryScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/inventoryScreen.ui index 2afd65723..2be50a95b 100644 --- a/engine/src/main/resources/org/destinationsol/assets/ui/inventoryScreen.ui +++ b/engine/src/main/resources/org/destinationsol/assets/ui/inventoryScreen.ui @@ -5,7 +5,7 @@ "type": "RelativeLayout", "contents": [ { - "type": "UIBox", + "type": "UIBackingBox", "family": "menuBox", "content": { "type": "RelativeLayout", From 3537cece20a63584a4c30e4824cc86c8ba54cc16 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Wed, 10 Nov 2021 21:54:12 +0000 Subject: [PATCH 3/5] fix(InventoryScreen): fix inventory not updating when dropping last item row on screen --- .../ui/nui/screens/InventoryScreen.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java index 868bcf477..219aca8be 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java @@ -304,13 +304,12 @@ public void setSelected(List itemGroup) { ItemContainer items = inventoryOperations.getItems(solApplication.getGame()); if (!items.containsGroup(itemGroup)) { selectedIndex = 0; - return; - } - - for (int groupNo = 0; groupNo < items.groupCount(); groupNo++) { - if (items.getGroup(groupNo) == itemGroup) { - page = groupNo / Const.ITEM_GROUPS_PER_PAGE; - selectedIndex = groupNo % Const.ITEM_GROUPS_PER_PAGE; + } else { + for (int groupNo = 0; groupNo < items.groupCount(); groupNo++) { + if (items.getGroup(groupNo) == itemGroup) { + page = groupNo / Const.ITEM_GROUPS_PER_PAGE; + selectedIndex = groupNo % Const.ITEM_GROUPS_PER_PAGE; + } } } From 113fab4016407272403a583d16a9f0c0ff6e6fd6 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sat, 13 Nov 2021 17:17:29 +0000 Subject: [PATCH 4/5] feat(nui): convert the game menu screen to NUI --- .../org/destinationsol/SolApplication.java | 5 +- .../game/screens/GameScreens.java | 3 +- .../game/screens/MainGameScreen.java | 6 +- .../game/screens/MenuScreen.java | 100 ------------------ .../destinationsol/ui/SolInputManager.java | 13 ++- .../ui/nui/screens/MainGameScreen.java | 5 +- .../ui/nui/screens/MenuScreen.java | 90 ++++++++++++++++ .../nui/screens/mainMenu/OptionsScreen.java | 2 +- .../assets/skins/mainGameScreen.skin | 16 +++ .../destinationsol/assets/ui/menuScreen.ui | 74 +++++++++++++ 10 files changed, 202 insertions(+), 112 deletions(-) delete mode 100644 engine/src/main/java/org/destinationsol/game/screens/MenuScreen.java create mode 100644 engine/src/main/java/org/destinationsol/ui/nui/screens/MenuScreen.java create mode 100644 engine/src/main/resources/org/destinationsol/assets/ui/menuScreen.ui diff --git a/engine/src/main/java/org/destinationsol/SolApplication.java b/engine/src/main/java/org/destinationsol/SolApplication.java index bb0b59af8..7c1f5ebab 100644 --- a/engine/src/main/java/org/destinationsol/SolApplication.java +++ b/engine/src/main/java/org/destinationsol/SolApplication.java @@ -402,9 +402,12 @@ public SolLayouts getLayouts() { public void finishGame() { solGame.onGameEnd(context); - solGame = null; + // TODO: remove the following line when all screens have been ported to use NUI inputManager.setScreen(this, null); + inputManager.update(this); // Force an update to remove all the InputManager UI screens + + solGame = null; nuiManager.pushScreen(menuScreens.main); } diff --git a/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java b/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java index c5178173a..93870a4b7 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java +++ b/engine/src/main/java/org/destinationsol/game/screens/GameScreens.java @@ -19,6 +19,7 @@ import org.destinationsol.game.context.Context; import org.destinationsol.ui.SolLayouts; import org.destinationsol.ui.nui.screens.InventoryScreen; +import org.destinationsol.ui.nui.screens.MenuScreen; public class GameScreens { public final MainGameScreen mainGameScreen; @@ -34,7 +35,7 @@ public GameScreens(SolApplication cmp, Context context) { RightPaneLayout rightPaneLayout = layouts.rightPaneLayout; mainGameScreen = new MainGameScreen(rightPaneLayout, context); mapScreen = new MapScreen(rightPaneLayout, cmp.isMobile(), cmp.getOptions()); - menuScreen = new MenuScreen(layouts.menuLayout, cmp.getOptions()); + menuScreen = (MenuScreen) cmp.getNuiManager().createScreen("engine:menuScreen"); inventoryScreen = (org.destinationsol.ui.nui.screens.InventoryScreen) cmp.getNuiManager().createScreen("engine:inventoryScreen"); talkScreen = new TalkScreen(layouts.menuLayout, cmp.getOptions()); waypointCreationScreen = new WaypointCreationScreen(layouts.menuLayout, cmp.getOptions(), mapScreen); diff --git a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java index f662a82a8..4e1209476 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java @@ -48,6 +48,7 @@ import org.destinationsol.ui.SolUiControl; import org.destinationsol.ui.SolUiScreen; import org.destinationsol.ui.UiDrawer; +import org.destinationsol.ui.nui.NUIManager; import org.destinationsol.ui.nui.NUIScreenLayer; import org.destinationsol.ui.nui.screens.ConsoleScreen; import org.destinationsol.ui.nui.screens.UIShipControlsScreen; @@ -217,6 +218,7 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi } SolGame game = solApplication.getGame(); SolInputManager inputMan = solApplication.getInputManager(); + NUIManager nuiManager = solApplication.getNuiManager(); GameScreens screens = game.getScreens(); Hero hero = game.getHero(); @@ -226,7 +228,7 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi zoneNameAnnouncer.update(game, context); - NUIScreenLayer topScreen = solApplication.getNuiManager().getTopScreen(); + NUIScreenLayer topScreen = nuiManager.getTopScreen(); boolean controlsEnabled = inputMan.getTopScreen() == this && (topScreen instanceof org.destinationsol.ui.nui.screens.MainGameScreen || topScreen instanceof UIShipControlsScreen); shipControl.update(solApplication, controlsEnabled); @@ -235,7 +237,7 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi if (solApplication.getNuiManager().hasScreenOfType(ConsoleScreen.class)) { controls.forEach(x -> x.setEnabled(false)); - } else if (!inputMan.isScreenOn(screens.menuScreen)) { + } else if (!nuiManager.hasScreen(screens.menuScreen)) { game.setPaused(false); controls.forEach(x -> x.setEnabled(true)); } diff --git a/engine/src/main/java/org/destinationsol/game/screens/MenuScreen.java b/engine/src/main/java/org/destinationsol/game/screens/MenuScreen.java deleted file mode 100644 index 34e4c569a..000000000 --- a/engine/src/main/java/org/destinationsol/game/screens/MenuScreen.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.game.screens; - -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.SolGame; -import org.destinationsol.menu.MenuLayout; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -public class MenuScreen extends SolUiBaseScreen { - private final SolUiControl closeControl; - private final SolUiControl exitControl; - private final SolUiControl respawnControl; - private final SolUiControl soundVolControl; - private final SolUiControl musicVolumeControl; - private final SolUiControl doNotSellEquippedControl; - - public MenuScreen(MenuLayout menuLayout, GameOptions gameOptions) { - doNotSellEquippedControl = new SolUiControl(menuLayout.buttonRect(-1, -1), true); - doNotSellEquippedControl.setDisplayName("Can sell used items"); - controls.add(doNotSellEquippedControl); - soundVolControl = new SolUiControl(menuLayout.buttonRect(-1, 1), true); - soundVolControl.setDisplayName("Sound Volume"); - controls.add(soundVolControl); - musicVolumeControl = new SolUiControl(menuLayout.buttonRect(-1, 0), true); - musicVolumeControl.setDisplayName("Music Volume"); - controls.add(musicVolumeControl); - respawnControl = new SolUiControl(menuLayout.buttonRect(-1, 2), true); - respawnControl.setDisplayName("Respawn"); - controls.add(respawnControl); - exitControl = new SolUiControl(menuLayout.buttonRect(-1, 3), true); - exitControl.setDisplayName("Exit"); - controls.add(exitControl); - closeControl = new SolUiControl(menuLayout.buttonRect(-1, 4), true, gameOptions.getKeyClose()); - closeControl.setDisplayName("Resume"); - controls.add(closeControl); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - SolGame game = solApplication.getGame(); - game.setPaused(true); - SolInputManager im = solApplication.getInputManager(); - GameOptions options = solApplication.getOptions(); - soundVolControl.setDisplayName("Sound Volume: " + options.sfxVolume.getName()); - if (soundVolControl.isJustOff()) { - options.advanceSoundVolMul(); - } - musicVolumeControl.setDisplayName("Music Volume: " + options.musicVolume.getName()); - if (musicVolumeControl.isJustOff()) { - options.advanceMusicVolMul(); - solApplication.getMusicManager().changeVolume(options); - } - if (respawnControl.isJustOff()) { - game.respawn(); - im.setScreen(solApplication, game.getScreens().mainGameScreen); - game.setPaused(false); - } - if (exitControl.isJustOff()) { - solApplication.finishGame(); - } - if (closeControl.isJustOff()) { - game.setPaused(false); - im.setScreen(solApplication, game.getScreens().mainGameScreen); - } - doNotSellEquippedControl.setDisplayName("Can sell used items: " + - (options.canSellEquippedItems ? "Yes" : "No")); - if (doNotSellEquippedControl.isJustOff()) { - options.canSellEquippedItems = !options.canSellEquippedItems; - } - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(uiDrawer.filler, SolColor.UI_BG); - } - - @Override - public boolean isCursorOnBackground(SolInputManager.InputPointer inputPointer) { - return true; - } -} diff --git a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java index 849d1a514..8e716ca09 100644 --- a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java +++ b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java @@ -33,6 +33,7 @@ import org.destinationsol.common.SolMath; import org.destinationsol.game.SolGame; import org.destinationsol.game.context.Context; +import org.destinationsol.ui.nui.NUIManager; import java.util.ArrayList; import java.util.List; @@ -192,7 +193,8 @@ public void update(SolApplication solApplication) { // This keeps the mouse within the window, but only when playing the game with the mouse. // All other times the mouse can freely leave and return. - if (!mobile && solApplication.getOptions().controlType == GameOptions.ControlType.MIXED && game != null && getTopScreen() != game.getScreens().menuScreen) { + if (!mobile && solApplication.getOptions().controlType == GameOptions.ControlType.MIXED && game != null && + solApplication.getNuiManager().getTopScreen() != game.getScreens().menuScreen) { if (!Gdx.input.isCursorCatched() && !osIsLinux) { Gdx.input.setCursorCatched(true); } @@ -286,11 +288,12 @@ private void updateCursor(SolApplication solApplication) { if (solApplication.isMobile()) { return; } + NUIManager nuiManager = solApplication.getNuiManager(); SolGame game = solApplication.getGame(); mousePos.set(inputPointers[0].x, inputPointers[0].y); if (solApplication.getOptions().controlType == GameOptions.ControlType.MIXED || solApplication.getOptions().controlType == GameOptions.ControlType.MOUSE) { - if (game == null || mouseOnUi) { + if (game == null || mouseOnUi || nuiManager.isMouseOnUi()) { currCursor = uiCursor; } else { currCursor = game.getScreens().mainGameScreen.getShipControl().getInGameTex(); @@ -300,7 +303,8 @@ private void updateCursor(SolApplication solApplication) { } return; } - if (mousePrevPos.epsilonEquals(mousePos, 0) && game != null && getTopScreen() != game.getScreens().menuScreen) { + if (mousePrevPos.epsilonEquals(mousePos, 0) && game != null && + nuiManager.getTopScreen() != game.getScreens().menuScreen) { mouseIdleTime += Const.REAL_TIME_STEP; currCursor = mouseIdleTime < CURSOR_SHOW_TIME ? uiCursor : null; } else { @@ -359,7 +363,8 @@ public void draw(UiDrawer uiDrawer, SolApplication solApplication) { SolGame game = solApplication.getGame(); TutorialManager tutorialManager = game == null ? null : context.get(TutorialManager.class); - if (tutorialManager != null && getTopScreen() != game.getScreens().menuScreen) { + if (tutorialManager != null && + solApplication.getNuiManager().getTopScreen() != game.getScreens().menuScreen) { tutorialManager.draw(uiDrawer); } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index a8b31260c..d7b9fc551 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -106,7 +106,7 @@ public void update(float delta) { super.update(delta); SolInputManager solInputManager = solApplication.getInputManager(); GameScreens gameScreens = solApplication.getGame().getScreens(); - if (!solInputManager.isScreenOn(gameScreens.menuScreen) && + if (!nuiManager.hasScreen(gameScreens.menuScreen) && !solInputManager.isScreenOn(gameScreens.mapScreen)) { ((AbstractWidget) contents).setVisible(true); } else { @@ -260,10 +260,9 @@ public UIWarnButton getMercsButton() { } private void onMenuButtonClicked(UIWidget widget) { - SolInputManager solInputManager = solApplication.getInputManager(); GameScreens gameScreens = solApplication.getGame().getScreens(); - solInputManager.setScreen(solApplication, gameScreens.menuScreen); + nuiManager.pushScreen(gameScreens.menuScreen); } private void onMapButtonClicked(UIWidget widget) { diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MenuScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MenuScreen.java new file mode 100644 index 000000000..7a41ccf5e --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MenuScreen.java @@ -0,0 +1,90 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.ui.nui.screens; + +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; + +/** + * This is the game menu, accessible from anytime in-game by pressing the menu key (default "Escape"). + * The game menu allows you to configure volume options, trigger a respawn or exit to the main menu. + */ +public class MenuScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + + @Override + public void initialise() { + UIButton canSellUsedItemsButton = find("canSellUsedItemsButton", UIButton.class); + canSellUsedItemsButton.setText("Can sell used items: " + (solApplication.getOptions().canSellEquippedItems ? "Yes" : "No")); + canSellUsedItemsButton.subscribe(button -> { + solApplication.getOptions().canSellEquippedItems = !solApplication.getOptions().canSellEquippedItems; + ((UIButton)button).setText("Can sell used items: " + (solApplication.getOptions().canSellEquippedItems ? "Yes" : "No")); + }); + + UIButton soundVolumeButton = find("soundVolumeButton", UIButton.class); + soundVolumeButton.setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); + soundVolumeButton.subscribe(button -> { + solApplication.getOptions().advanceSoundVolMul(); + ((UIButton)button).setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); + }); + + UIButton musicVolumeButton = find("musicVolumeButton", UIButton.class); + musicVolumeButton.setText("Music Volume: " + solApplication.getOptions().musicVolume.getName()); + musicVolumeButton.subscribe(button -> { + solApplication.getOptions().advanceMusicVolMul(); + ((UIButton)button).setText("Music Volume: " + solApplication.getOptions().musicVolume.getName()); + solApplication.getMusicManager().changeVolume(solApplication.getOptions()); + }); + + UIButton respawnButton = find("respawnButton", UIButton.class); + respawnButton.subscribe(button -> { + solApplication.getGame().respawn(); + nuiManager.removeScreen(this); + }); + + UIButton exitButton = find("exitButton", UIButton.class); + exitButton.subscribe(button -> { + solApplication.finishGame(); + }); + + KeyActivatedButton resumeButton = find("resumeButton", KeyActivatedButton.class); + resumeButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyClose())); + resumeButton.subscribe(button -> { + nuiManager.removeScreen(this); + }); + } + + @Override + public void onAdded() { + solApplication.getGame().setPaused(true); + } + + @Override + public void onRemoved() { + solApplication.getGame().setPaused(false); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java index 314cbbd9a..08888bf9f 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java @@ -49,7 +49,7 @@ public void initialise() { UIButton soundVolumeButton = find("soundVolumeButton", UIButton.class); soundVolumeButton.setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); soundVolumeButton.subscribe(button -> { - solApplication.getOptions().advanceMusicVolMul(); + solApplication.getOptions().advanceSoundVolMul(); soundVolumeButton.setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); }); diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin index 1cbc58ccd..6e486b0fd 100644 --- a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin +++ b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin @@ -13,6 +13,22 @@ "controlsUIButton": { "font": "engine:main#0.95" }, + "unrestrictedMenuBox": { + "elements": { + "UIBox": { + "background": "engine:background" + } + } + }, + "menuUIButton": { + "elements": { + "UIButton": { + "max-width": 640, + "max-height": 128 + } + }, + "font": "engine:main#1" + }, "menuBox": { "max-width": 800, "max-height": 600, diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/menuScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/menuScreen.ui new file mode 100644 index 000000000..c5893a061 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/menuScreen.ui @@ -0,0 +1,74 @@ +{ + "type": "MenuScreen", + "skin": "engine:mainGameScreen", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UIBackingBox", + "family": "unrestrictedMenuBox", + "layoutInfo": { + "position-top": {}, + "position-bottom": {}, + "position-left": {}, + "position-right": {} + } + }, + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuUIButton", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "UIButton", + "id": "canSellUsedItemsButton", + "text": "Can sell used items" + }, + { + "type": "UIButton", + "id": "soundVolumeButton", + "text": "Sound Volume" + }, + { + "type": "UIButton", + "id": "musicVolumeButton", + "text": "Music Volume" + }, + { + "type": "UIButton", + "id": "respawnButton", + "text": "Respawn" + }, + { + "type": "UIButton", + "id": "exitButton", + "text": "Exit" + }, + { + "type": "KeyActivatedButton", + "id": "resumeButton", + "text": "Resume" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "position-top": { + "target": "MIDDLE", + "offset": -64 + }, + "position-left": { + "offset": 64 + }, + "position-right": { + "offset": 64 + } + } + } + ] + } +} \ No newline at end of file From aec00c2c7c9aa18fee9dd3943c99ff04b703f0de Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Tue, 16 Nov 2021 21:20:47 +0000 Subject: [PATCH 5/5] fix(GameMenu): fix the UI cursor not showing in the game menu --- .../org/destinationsol/ui/nui/NUIManager.java | 12 +++--- .../ui/nui/screens/InventoryScreen.java | 8 ++++ .../ui/nui/screens/MainGameScreen.java | 40 +++++++------------ 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java index b9d33d526..e0471d967 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java @@ -53,7 +53,6 @@ import org.terasology.nui.events.NUIMouseButtonEvent; import org.terasology.nui.events.NUIMouseWheelEvent; import org.terasology.nui.skin.UISkin; -import org.terasology.nui.util.RectUtility; import org.terasology.nui.widgets.UIButton; import org.terasology.nui.widgets.UIText; @@ -226,9 +225,13 @@ public void update(SolApplication solApplication) { for (MouseAction action : mouse.getInputQueue()) { if (action.getInput().getType() == InputType.MOUSE_BUTTON) { if (action.getState().isDown()) { - canvas.processMouseClick((MouseInput) action.getInput(), action.getMousePosition(), action.getPointer()); + if (canvas.processMouseClick((MouseInput) action.getInput(), action.getMousePosition(), action.getPointer())) { + continue; + } } else { - canvas.processMouseRelease((MouseInput) action.getInput(), action.getMousePosition(), action.getPointer()); + if (canvas.processMouseRelease((MouseInput) action.getInput(), action.getMousePosition(), action.getPointer())) { + continue; + } } NUIMouseButtonEvent event = new NUIMouseButtonEvent((MouseInput) action.getInput(), action.getState(), action.getMousePosition()); @@ -433,10 +436,9 @@ public void setContext(Context context) { * @return true, if the mouse is currently over an interactive UI element, otherwise false */ public boolean isMouseOnUi() { - // TODO: Find better way of doing this. Vector2i mousePosition = mouse.getPosition(); for (Rectanglei interactionRegion : canvas.getInteractionRegions()) { - if (!interactionRegion.equals(canvas.getRegion()) && interactionRegion.containsPoint(mousePosition)) { + if (interactionRegion.containsPoint(mousePosition)) { return true; } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java index 219aca8be..df7e4448b 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/InventoryScreen.java @@ -176,6 +176,14 @@ public void onAdded() { updateItemRows(); } + /** + * Returns the current {@link InventoryOperationsScreen operations screen} being applied to this screen. + * @return the current operations screen + */ + public InventoryOperationsScreen getOperations() { + return inventoryOperations; + } + /** * Assigns the specified {@link InventoryOperationsScreen operations screen} to this screen. * @param operations the operations that can be performed diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index d7b9fc551..9ad86807b 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -28,20 +28,14 @@ import org.destinationsol.game.ship.SolShip; import org.destinationsol.ui.SolInputManager; import org.destinationsol.ui.nui.NUIScreenLayer; -import org.destinationsol.ui.nui.widgets.KeyActivatedButton; import org.destinationsol.ui.nui.widgets.UIWarnButton; -import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.input.ButtonState; import org.terasology.input.Keyboard; import org.terasology.nui.AbstractWidget; -import org.terasology.nui.BaseInteractionListener; -import org.terasology.nui.Canvas; -import org.terasology.nui.InteractionListener; import org.terasology.nui.UIWidget; -import org.terasology.nui.asset.UIElement; import org.terasology.nui.backends.libgdx.GDXInputUtil; import org.terasology.nui.events.NUIKeyEvent; -import org.terasology.nui.events.NUIMouseClickEvent; +import org.terasology.nui.events.NUIMouseButtonEvent; import java.util.List; @@ -62,18 +56,6 @@ public class MainGameScreen extends NUIScreenLayer { @In private SolApplication solApplication; - private final InteractionListener interactionListener = new BaseInteractionListener() { - @Override - public boolean onMouseClick(NUIMouseClickEvent event) { - NUIScreenLayer topScreen = nuiManager.getTopScreen(); - if (topScreen != MainGameScreen.this && !(topScreen instanceof UIShipControlsScreen)) { - nuiManager.popScreen(); - return true; - } - return false; - } - }; - @Override public void initialise() { consoleScreen = (ConsoleScreen) nuiManager.createScreen("engine:console"); @@ -174,12 +156,6 @@ public void update(float delta) { } } - @Override - public void onDraw(Canvas canvas) { - canvas.addInteractionRegion(interactionListener); - super.onDraw(canvas); - } - @Override protected boolean escapeCloses() { return false; @@ -210,6 +186,18 @@ public boolean onKeyEvent(NUIKeyEvent event) { return super.onKeyEvent(event); } + @Override + public void onMouseButtonEvent(NUIMouseButtonEvent event) { + if (event.getState() == ButtonState.UP) { + NUIScreenLayer topScreen = nuiManager.getTopScreen(); + if (!solApplication.getInputManager().isMouseOnUi() && + topScreen != MainGameScreen.this && !(topScreen instanceof UIShipControlsScreen)) { + nuiManager.popScreen(); + event.consume(); + } + } + } + @Override public void onRemoved() { menuButton.unsubscribe(this::onMenuButtonClicked); @@ -306,6 +294,8 @@ private void onMercsButtonClicked(UIWidget widget) { gameScreens.inventoryScreen.setOperations(gameScreens.inventoryScreen.getChooseMercenaryScreen()); nuiManager.pushScreen(gameScreens.inventoryScreen); solApplication.getGame().getHero().getMercs().markAllAsSeen(); + } else { + nuiManager.removeScreen(gameScreens.inventoryScreen); } } }