diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java index 95c431476..81147b413 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java @@ -66,6 +66,8 @@ public class EnergyCrystal extends Item { Sample.INSTANCE.play( Assets.Sounds.ITEM ); + updateQuickslot(); + return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java index 8fe09a1be..136b4e4e1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java @@ -73,6 +73,7 @@ public class Gold extends Item { hero.spendAndNext( TIME_TO_PICK_UP ); Sample.INSTANCE.play( Assets.Sounds.GOLD, 1, 1, Random.Float( 0.9f, 1.1f ) ); + updateQuickslot(); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java index 2ddff1447..0f76291e8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java @@ -41,6 +41,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.MissileSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.InventoryPane; import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton; import com.watabou.noosa.audio.Sample; import com.watabou.noosa.particles.Emitter; @@ -227,8 +228,8 @@ public class Item implements Bundlable { items.add( this ); Dungeon.quickslot.replacePlaceholder(this); - updateQuickslot(); Collections.sort( items, itemComparator ); + updateQuickslot(); return true; } @@ -287,13 +288,13 @@ public class Item implements Bundlable { public final Item detachAll( Bag container ) { Dungeon.quickslot.clearItem( this ); - updateQuickslot(); for (Item item : container.items) { if (item == this) { container.items.remove(this); item.onDetach(); container.grabItems(); //try to put more items into the bag as it now has free space + updateQuickslot(); return this; } else if (item instanceof Bag) { Bag bag = (Bag)item; @@ -302,7 +303,8 @@ public class Item implements Bundlable { } } } - + + updateQuickslot(); return this; } @@ -489,6 +491,7 @@ public class Item implements Bundlable { public static void updateQuickslot() { QuickSlotButton.refresh(); + InventoryPane.refresh(); } private static final String QUANTITY = "quantity"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/InventoryPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/InventoryPane.java new file mode 100644 index 000000000..68478b0d7 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/InventoryPane.java @@ -0,0 +1,377 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2022 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.ui; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Chrome; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LostInventory; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings; +import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem; +import com.shatteredpixel.shatteredpixeldungeon.items.Gold; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.MagicalHolster; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.PotionBandolier; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.ScrollHolder; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.VelvetPouch; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; +import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndUseItem; +import com.watabou.gltextures.TextureCache; +import com.watabou.input.PointerEvent; +import com.watabou.noosa.BitmapText; +import com.watabou.noosa.ColorBlock; +import com.watabou.noosa.Game; +import com.watabou.noosa.Gizmo; +import com.watabou.noosa.Image; +import com.watabou.noosa.NinePatch; +import com.watabou.noosa.PointerArea; +import com.watabou.noosa.audio.Sample; +import com.watabou.noosa.ui.Component; + +import java.util.ArrayList; + +public class InventoryPane extends Component { + + private NinePatch bg; + private NinePatch bg2; //2 backgrounds to reduce transparency + + private static InventoryPane instance; + + private ArrayList equipped; + private ArrayList bagItems; + + private Image gold; + private BitmapText goldTxt; + private Image energy; + private BitmapText energyTxt; + + private ArrayList bags; + + public static final int WIDTH = 187; + public static final int HEIGHT = 82; + + private static final int SLOT_WIDTH = 17; + private static final int SLOT_HEIGHT = 24; + + public static Bag lastBag; + + private boolean lastEnabled = true; + + public InventoryPane(){ + super(); + instance = this; + } + + @Override + public synchronized void destroy() { + super.destroy(); + if (instance == this) instance = null; + } + + @Override + protected void createChildren() { + + //TODO capture inputs tapped on BG + + bg = Chrome.get(Chrome.Type.TOAST_TR); + add(bg); + + bg2 = Chrome.get(Chrome.Type.TOAST_TR); + add(bg2); + + //blocks touches from going through BG into game scene + add (new PointerArea(bg)); + + equipped = new ArrayList<>(); + for (int i = 0; i < 5; i++){ + InventorySlot btn = new InventorySlot(null){ + @Override + protected void onClick() { + if (lastBag != item && !lastBag.contains(item) && !item.isEquipped(Dungeon.hero)){ + updateInventory(); + } else { + Game.scene().addToFront(new WndUseItem( null, item ) ); + } + } + }; + equipped.add(btn); + add(btn); + } + + gold = Icons.get(Icons.COIN_SML); + add(gold); + goldTxt = new BitmapText(PixelScene.pixelFont); + goldTxt.hardlight(Window.TITLE_COLOR); + add(goldTxt); + + energy = Icons.get(Icons.ENERGY_SML); + add(energy); + energyTxt = new BitmapText(PixelScene.pixelFont); + energyTxt.hardlight(0x44CCFF); + add(energyTxt); + + bagItems = new ArrayList<>(); + for (int i = 0; i < 20; i++){ + InventorySlot btn = new InventorySlot(null){ + @Override + protected void onClick() { + if (lastBag != item && !lastBag.contains(item) && !item.isEquipped(Dungeon.hero)){ + updateInventory(); + } else { + Game.scene().addToFront(new WndUseItem( null, item ) ); + } + } + }; + bagItems.add(btn); + add(btn); + } + + bags = new ArrayList<>(); + for (int i = 0; i < 5; i++){ + BagButton btn = new BagButton(null); + bags.add(btn); + add(btn); + } + + updateInventory(); + + width = WIDTH; + height = HEIGHT; + } + + @Override + protected void layout() { + width = WIDTH; + height = HEIGHT; + + bg.x = bg2.x = x; + bg.y = bg2.y = y; + bg.size(width, height); + bg2.size(width, height); + + float left = x+4; + for (InventorySlot i : equipped){ + i.setRect(left, y+4, SLOT_WIDTH, SLOT_HEIGHT); + left = i.right()+1; + } + + goldTxt.x = left; + goldTxt.y = y+5.5f; + PixelScene.align(goldTxt); + + gold.x = goldTxt.x + goldTxt.width() + 1; + gold.y = goldTxt.y; + + energyTxt.x = gold.x + gold.width() + 2; + energyTxt.y = y+5.5f; + PixelScene.align(energyTxt); + + energy.x = energyTxt.x + energyTxt.width() + 1; + energy.y = energyTxt.y; + + for (BagButton b : bags){ + b.setRect(left, y + 14, SLOT_WIDTH, 14); + left = b.right()+1; + } + + left = x+4; + float top = y+4+SLOT_HEIGHT+1; + for (InventorySlot b : bagItems){ + b.setRect(left, top, SLOT_WIDTH, SLOT_HEIGHT); + left = b.right()+1; + if (left - x > width - 17){ + left = x+4; + top += SLOT_HEIGHT+1; + } + } + + super.layout(); + } + + public static void refresh(){ + if (instance != null) instance.updateInventory(); + } + + public void updateInventory(){ + Belongings stuff = Dungeon.hero.belongings; + + if (lastBag == null || !stuff.contains(lastBag)){ + lastBag = stuff.backpack; + } + + equipped.get(0).item(stuff.weapon == null ? new WndBag.Placeholder( ItemSpriteSheet.WEAPON_HOLDER ) : stuff.weapon); + equipped.get(1).item(stuff.armor == null ? new WndBag.Placeholder( ItemSpriteSheet.ARMOR_HOLDER ) : stuff.armor); + equipped.get(2).item(stuff.artifact == null ? new WndBag.Placeholder( ItemSpriteSheet.ARTIFACT_HOLDER ) : stuff.artifact); + equipped.get(3).item(stuff.misc == null ? new WndBag.Placeholder( ItemSpriteSheet.SOMETHING ) : stuff.misc); + equipped.get(4).item(stuff.ring == null ? new WndBag.Placeholder( ItemSpriteSheet.RING_HOLDER ) : stuff.ring); + + ArrayList items = lastBag.items; + int j = 0; + for (int i = 0; i < 20; i++){ + if (i == 0 && lastBag != stuff.backpack){ + bagItems.get(i).item(lastBag); + continue; + } + if (items.size() > j){ + if (items.get(j) instanceof Bag){ + j++; + i--; + continue; + } + bagItems.get(i).item(items.get(j)); + j++; + } else { + bagItems.get(i).item(null); + } + } + + goldTxt.text(Integer.toString(Dungeon.gold)); + goldTxt.measure(); + + energyTxt.text(Integer.toString(Dungeon.energy)); + energyTxt.measure(); + energyTxt.visible = energy.visible = Dungeon.energy > 0; + + ArrayList inventBags = stuff.getBags(); + for (int i = 0; i < bags.size(); i++){ + if (inventBags.size() > i){ + bags.get(i).bag(inventBags.get(i)); + } else { + bags.get(i).bag(null); + } + } + + for (InventorySlot b : equipped){ + b.enable(lastEnabled && !(b.item() instanceof WndBag.Placeholder)); + } + for (InventorySlot b : bagItems){ + b.enable(lastEnabled && b.item() != null); + } + for (BagButton b : bags){ + b.enable(lastEnabled); + } + + layout(); + } + + @Override + public synchronized void update() { + super.update(); + + if (lastEnabled != (Dungeon.hero.ready || !Dungeon.hero.isAlive())) { + lastEnabled = (Dungeon.hero.ready || !Dungeon.hero.isAlive()); + + for (InventorySlot b : equipped){ + b.enable(lastEnabled && !(b.item() instanceof WndBag.Placeholder)); + } + for (InventorySlot b : bagItems){ + b.enable(lastEnabled && b.item() != null); + } + for (BagButton b : bags){ + b.enable(lastEnabled); + } + } + + } + + private Image bagIcon(Bag bag ) { + if (bag instanceof VelvetPouch) { + return Icons.get( Icons.SEED_POUCH ); + } else if (bag instanceof ScrollHolder) { + return Icons.get( Icons.SCROLL_HOLDER ); + } else if (bag instanceof MagicalHolster) { + return Icons.get( Icons.WAND_HOLSTER ); + } else if (bag instanceof PotionBandolier) { + return Icons.get( Icons.POTION_BANDOLIER ); + } else { + return Icons.get( Icons.BACKPACK ); + } + } + + private class BagButton extends IconButton { + + private static final int ACTIVE = 0x9953564D; + private static final int INACTIVE = 0x9942443D; + + private ColorBlock bgTop; + private ColorBlock bgBottom; + + private Bag bag; + + public BagButton( Bag bag ){ + super( bagIcon(bag) ); + this.bag = bag; + visible = active = bag != null; + } + + public void bag( Bag bag ){ + this.bag = bag; + icon(bagIcon(bag)); + visible = active = bag != null; + + if (lastBag == bag){ + bgTop.texture(TextureCache.createSolid(ACTIVE)); + bgBottom.texture(TextureCache.createSolid(ACTIVE)); + } else { + bgTop.texture(TextureCache.createSolid(INACTIVE)); + bgBottom.texture(TextureCache.createSolid(INACTIVE)); + } + } + + @Override + protected void createChildren() { + super.createChildren(); + + bgTop = new ColorBlock(1, 1, ACTIVE); + add(bgTop); + + bgBottom = new ColorBlock(1, 1, ACTIVE); + add(bgBottom); + } + + @Override + protected void layout() { + super.layout(); + + bgTop.size(width-2, 1); + bgTop.y = y; + bgTop.x = x+1; + + bgBottom.size(width, height-1); + bgBottom.y = y+1; + bgBottom.x = x; + } + + @Override + protected void onClick() { + super.onClick(); + lastBag = bag; + refresh(); + } + + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndUseItem.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndUseItem.java index a84f9a4ea..03c6ceb47 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndUseItem.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndUseItem.java @@ -53,6 +53,7 @@ public class WndUseItem extends WndInfoItem { if (Dungeon.hero.isAlive() && Dungeon.hero.belongings.contains(item)){ item.execute( Dungeon.hero, action ); } + Item.updateQuickslot(); } }; btn.setSize( btn.reqWidth(), BUTTON_HEIGHT );