diff --git a/core/src/main/assets/items.png b/core/src/main/assets/items.png index ed22377bb..a460e5204 100644 Binary files a/core/src/main/assets/items.png and b/core/src/main/assets/items.png differ diff --git a/core/src/main/assets/menu_button.png b/core/src/main/assets/menu_button.png index 5d086c459..90b5c7f3e 100644 Binary files a/core/src/main/assets/menu_button.png and b/core/src/main/assets/menu_button.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 2295cd3db..9297fd243 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -110,7 +110,6 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.HeroSprite; import com.shatteredpixel.shatteredpixeldungeon.ui.AttackIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton; -import com.shatteredpixel.shatteredpixeldungeon.ui.StatusPane; import com.shatteredpixel.shatteredpixeldungeon.utils.BArray; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.windows.WndAlchemy; @@ -1467,7 +1466,7 @@ public class Hero extends Char { Notes.remove(new SkeletonKey(Dungeon.depth)); Level.set( doorCell, Terrain.UNLOCKED_EXIT ); } - StatusPane.needsKeyUpdate = true; + GameScene.updateKeyDisplay(); Level.set( doorCell, door == Terrain.LOCKED_DOOR ? Terrain.DOOR : Terrain.UNLOCKED_EXIT ); GameScene.updateMap( doorCell ); @@ -1482,7 +1481,7 @@ public class Hero extends Char { } else if (heap.type == Type.CRYSTAL_CHEST){ Notes.remove(new CrystalKey(Dungeon.depth)); } - StatusPane.needsKeyUpdate = true; + GameScene.updateKeyDisplay(); heap.open( this ); } curAction = null; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java index 17ddc57e0..f380dcaa5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java @@ -26,7 +26,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; -import com.shatteredpixel.shatteredpixeldungeon.ui.StatusPane; import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal; import com.watabou.noosa.audio.Sample; import com.watabou.utils.Bundle; @@ -54,7 +53,7 @@ public abstract class Key extends Item { Notes.add(this); Sample.INSTANCE.play( Assets.SND_ITEM ); hero.spendAndNext( TIME_TO_PICK_UP ); - StatusPane.needsKeyUpdate = true; + GameScene.updateKeyDisplay(); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index c4714209e..4c74197d5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -746,6 +746,10 @@ public class GameScene extends PixelScene { public static void flashJournal(){ if (scene != null) scene.pane.flash(); } + + public static void updateKeyDisplay(){ + if (scene != null) scene.pane.updateKeys(); + } public static void resetMap() { if (scene != null) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/KeyDisplay.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/KeyDisplay.java new file mode 100644 index 000000000..220ae7606 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/KeyDisplay.java @@ -0,0 +1,217 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2017 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 android.graphics.RectF; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.CrystalKey; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.GoldenKey; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.Key; +import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey; +import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; +import com.watabou.gltextures.SmartTexture; +import com.watabou.gltextures.TextureCache; +import com.watabou.glwrap.Quad; +import com.watabou.glwrap.Vertexbuffer; +import com.watabou.noosa.NoosaScript; +import com.watabou.noosa.Visual; + +import java.nio.FloatBuffer; +import java.util.HashMap; + +public class KeyDisplay extends Visual { + + private float[] vertices = new float[16]; + private FloatBuffer quads; + private Vertexbuffer buffer; + + private SmartTexture tx = TextureCache.get(Assets.MENU); + + private boolean dirty = true; + private int[] keys; + + //mapping of key types to slots in the array, 0 is reserved for black (missed) keys + //this also determines the order these keys will appear (lower first) + //and the order they will be truncated if there is no space (higher first, larger counts first) + private static final HashMap, Integer> keyMap = new HashMap<>(); + static { + keyMap.put(SkeletonKey.class, 1); + keyMap.put(CrystalKey.class, 2); + keyMap.put(GoldenKey.class, 3); + keyMap.put(IronKey.class, 4); + } + + private int totalKeys = 0; + + public KeyDisplay() { + super(0, 0, 0, 0); + } + + public void updateKeys(){ + keys = new int[keyMap.size()+1]; + + for (Notes.KeyRecord rec : Notes.getRecords(Notes.KeyRecord.class)){ + if (rec.depth() < Dungeon.depth){ + //only ever 1 black key + keys[0] = 1; + } else if (rec.depth() == Dungeon.depth){ + keys[keyMap.get(rec.type())] += rec.quantity(); + } + } + + totalKeys = 0; + for (int k : keys){ + totalKeys += k; + } + dirty = true; + } + + public int keyCount(){ + return totalKeys; + } + + @Override + public void draw() { + super.draw(); + if (dirty){ + + updateVertices(); + + quads.limit(quads.position()); + if (buffer == null) + buffer = new Vertexbuffer(quads); + else + buffer.updateVertices(quads); + + } + + NoosaScript script = NoosaScript.get(); + + tx.bind(); + + script.camera( camera() ); + + script.uModel.valueM4( matrix ); + script.lighting( + rm, gm, bm, am, + ra, ga, ba, aa ); + script.drawQuadSet( buffer, totalKeys, 0 ); + } + + private void updateVertices(){ + //assumes shorter key sprite + int maxRows = (int)(height +1) / 5; + + //1 pixel of padding between each key + int maxPerRow = (int)(width + 1) / 4; + + int maxKeys = maxPerRow * maxRows; + + + while (totalKeys > maxKeys){ + Class mostType = null; + int mostNum = 0; + for (Class k : keyMap.keySet()){ + if (keys[keyMap.get(k)] >= mostNum){ + mostType = k; + mostNum = keys[keyMap.get(k)]; + } + } + keys[keyMap.get(mostType)]--; + totalKeys--; + } + + int rows = (int)Math.ceil(totalKeys / (float)maxPerRow); + + boolean shortKeys = (rows * 8) > height; + float left; + if (totalKeys > maxPerRow){ + left = 0; + } else { + left = (width + 1 - (totalKeys*4))/2; + } + float top = (height + 1 - (rows * (shortKeys ? 5 : 8)))/2; + quads = Quad.createSet(totalKeys); + for (int i = 0; i < totalKeys; i++){ + int keyIdx = 0; + + if (i == 0 && keys[0] > 0){ + //black key + keyIdx = 0; + + } else { + for (int j = 1; j < keys.length; j++){ + if (keys[j] > 0){ + keys[j]--; + keyIdx = j; + break; + } + } + } + + //texture coordinates + RectF r = tx.uvRect(43 + 3*keyIdx, shortKeys ? 8 : 0, + 46 + 3*keyIdx, shortKeys ? 12 : 7); + + vertices[2] = r.left; + vertices[3] = r.top; + + vertices[6] = r.right; + vertices[7] = r.top; + + vertices[10] = r.right; + vertices[11] = r.bottom; + + vertices[14] = r.left; + vertices[15] = r.bottom; + + //screen coordinates + vertices[0] = left; + vertices[1] = top; + + vertices[4] = left + 3; + vertices[5] = top; + + vertices[8] = left + 3; + vertices[9] = top + (shortKeys ? 4 : 7); + + vertices[12] = left; + vertices[13] = top + (shortKeys ? 4 : 7); + + quads.put(vertices); + + //move to the right for more keys, drop down if the row is done + left += 4; + if (left + 3 > width){ + left = 0; + top += (shortKeys ? 5 : 8); + } + } + + dirty = false; + + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index e3888d4bb..683a63321 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -27,8 +27,6 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.items.Item; -import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey; -import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.HeroSprite; @@ -224,21 +222,23 @@ public class StatusPane extends Component { public void pickup( Item item, int cell) { pickedUp.reset( item, cell, - btnJournal.icon.x + btnJournal.icon.width()/2f, - btnJournal.icon.y + btnJournal.icon.height()/2f); + btnJournal.journalIcon.x + btnJournal.journalIcon.width()/2f, + btnJournal.journalIcon.y + btnJournal.journalIcon.height()/2f); } public void flash(){ btnJournal.flashing = true; } - - public static boolean needsKeyUpdate = false; + + public void updateKeys(){ + btnJournal.updateKeyDisplay(); + } private static class JournalButton extends Button { private Image bg; - //used to display key state to the player - private Image icon; + private Image journalIcon; + private KeyDisplay keyIcon; private boolean flashing; @@ -255,10 +255,13 @@ public class StatusPane extends Component { bg = new Image( Assets.MENU, 2, 2, 13, 11 ); add( bg ); - - icon = new Image( Assets.MENU, 31, 0, 11, 7); - add( icon ); - needsKeyUpdate = true; + + journalIcon = new Image( Assets.MENU, 31, 0, 11, 7); + add( journalIcon ); + + keyIcon = new KeyDisplay(); + add(keyIcon); + updateKeyDisplay(); } @Override @@ -267,10 +270,16 @@ public class StatusPane extends Component { bg.x = x + 13; bg.y = y + 2; - - icon.x = bg.x + (bg.width() - icon.width())/2f; - icon.y = bg.y + (bg.height() - icon.height())/2f; - PixelScene.align(icon); + + journalIcon.x = bg.x + (bg.width() - journalIcon.width())/2f; + journalIcon.y = bg.y + (bg.height() - journalIcon.height())/2f; + PixelScene.align(journalIcon); + + keyIcon.x = bg.x + 1; + keyIcon.y = bg.y + 1; + keyIcon.width = bg.width - 2; + keyIcon.height = bg.height - 2; + PixelScene.align(keyIcon); } private float time; @@ -278,11 +287,10 @@ public class StatusPane extends Component { @Override public void update() { super.update(); - if (needsKeyUpdate) - updateKeyDisplay(); if (flashing){ - icon.am = (float)Math.abs(Math.cos( 3 * (time += Game.elapsed) )); + journalIcon.am = (float)Math.abs(Math.cos( 3 * (time += Game.elapsed) )); + keyIcon.am = journalIcon.am; if (time >= 0.333f*Math.PI) { time = 0; } @@ -290,54 +298,29 @@ public class StatusPane extends Component { } public void updateKeyDisplay() { - needsKeyUpdate = false; - - boolean blackKey = false; - boolean specialKey = false; - int ironKeys = 0; - for (Notes.KeyRecord rec : Notes.getRecords(Notes.KeyRecord.class)){ - if (rec.depth() < Dungeon.depth){ - blackKey = true; - } else if (rec.depth() == Dungeon.depth){ - if (rec.type().equals(IronKey.class)) { - ironKeys += rec.quantity(); - } else { - specialKey = true; - } - } - } - - if (blackKey || specialKey || ironKeys > 0){ - int left = 46, top = 0, width = 0, height = 7; - if (blackKey){ - left = 43; - width += 3; - } - if (specialKey){ - top = 8; - width += 3; - } - width += ironKeys*3; - width = Math.min( width, 9); - icon.frame(left, top, width, height); + keyIcon.updateKeys(); + keyIcon.visible = keyIcon.keyCount() > 0; + journalIcon.visible = !keyIcon.visible; + if (keyIcon.keyCount() > 0) { + bg.brightness(.8f - (Math.min(6, keyIcon.keyCount()) / 20f)); } else { - icon.frame(31, 0, 11, 7); + bg.resetColor(); } - layout(); - } @Override protected void onTouchDown() { bg.brightness( 1.5f ); - icon.brightness( 1.5f ); Sample.INSTANCE.play( Assets.SND_CLICK ); } @Override protected void onTouchUp() { - bg.resetColor(); - icon.resetColor(); + if (keyIcon.keyCount() > 0) { + bg.brightness(.8f - (Math.min(6, keyIcon.keyCount()) / 20f)); + } else { + bg.resetColor(); + } } @Override