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 extends Key> 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