v2.4.0: added new buttons and bindings in the alchemy scene

This commit is contained in:
Evan Debenham
2024-03-06 14:30:46 -05:00
parent 340900abcb
commit 8efb48d83f
3 changed files with 262 additions and 13 deletions

View File

@@ -4,6 +4,12 @@ scenes.alchemyscene.title=Alchemy
scenes.alchemyscene.text=Combine ingredients to create something new!
scenes.alchemyscene.select=Select an item
scenes.alchemyscene.energy=Energy:
scenes.alchemyscene.add=Add Item
scenes.alchemyscene.no_items=There are no alchemizeable items in that bag.
scenes.alchemyscene.craft=Craft
scenes.alchemyscene.energize=Energize Items
scenes.alchemyscene.cancel=Cancel Ingredients
scenes.alchemyscene.repeat=Repeat Ingredients
scenes.amuletscene.exit=Let's call it a day
scenes.amuletscene.stay=I'm not done yet

View File

@@ -293,6 +293,17 @@ public class Item implements Bundlable {
return split;
}
}
public Item duplicate(){
Item dupe = Reflection.newInstance(getClass());
if (dupe == null){
return null;
}
Bundle copy = new Bundle();
this.storeInBundle(copy);
dupe.restoreFromBundle(copy);
return dupe;
}
public final Item detach( Bag container ) {

View File

@@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Chrome;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.SPDAction;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings;
@@ -34,24 +35,33 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.LiquidMetal;
import com.shatteredpixel.shatteredpixeldungeon.items.Recipe;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.AlchemistsToolkit;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.ui.Button;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.ItemSlot;
import com.shatteredpixel.shatteredpixeldungeon.ui.RadialMenu;
import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.Toolbar;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndEnergizeItem;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoItem;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndKeyBindings;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndMessage;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Blending;
import com.watabou.input.ControllerHandler;
import com.watabou.input.GameAction;
import com.watabou.input.KeyBindings;
import com.watabou.noosa.Camera;
import com.watabou.noosa.Game;
import com.watabou.noosa.Image;
@@ -72,7 +82,12 @@ public class AlchemyScene extends PixelScene {
private static final InputButton[] inputs = new InputButton[3];
private static final CombineButton[] combines = new CombineButton[3];
private static final OutputSlot[] outputs = new OutputSlot[3];
private IconButton cancel;
private IconButton repeat;
private static ArrayList<Item> lastIngredients = new ArrayList<>();
private static Recipe lastRecipe = null;
private Emitter smokeEmitter;
private Emitter bubbleEmitter;
private Emitter sparkEmitter;
@@ -121,6 +136,15 @@ public class AlchemyScene extends PixelScene {
im.scale.y = Camera.main.width;
add(im);
ExitButton btnExit = new ExitButton(){
@Override
protected void onClick() {
Game.switchScene(GameScene.class);
}
};
btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
add( btnExit );
bubbleEmitter = new Emitter();
bubbleEmitter.pos(0, 0, Camera.main.width, Camera.main.height);
bubbleEmitter.autoKill = false;
@@ -168,6 +192,143 @@ public class AlchemyScene extends PixelScene {
}
}
Button invSelector = new Button(){
@Override
protected void onClick() {
if (Dungeon.hero != null) {
ArrayList<Bag> bags = Dungeon.hero.belongings.getBags();
String[] names = new String[bags.size()];
Image[] images = new Image[bags.size()];
for (int i = 0; i < bags.size(); i++){
names[i] = Messages.titleCase(bags.get(i).name());
images[i] = new ItemSprite(bags.get(i));
}
String info = "";
if (ControllerHandler.controllerActive){
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.LEFT_CLICK, true)) + ": " + Messages.get(Toolbar.class, "container_select") + "\n";
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.BACK, true)) + ": " + Messages.get(Toolbar.class, "container_cancel");
} else {
info += Messages.get(WndKeyBindings.class, SPDAction.LEFT_CLICK.name()) + ": " + Messages.get(Toolbar.class, "container_select") + "\n";
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.BACK, false)) + ": " + Messages.get(Toolbar.class, "container_cancel");
}
Game.scene().addToFront(new RadialMenu(Messages.get(Toolbar.class, "container_prompt"), info, names, images){
@Override
public void onSelect(int idx, boolean alt) {
super.onSelect(idx, alt);
Bag bag = bags.get(idx);
ArrayList<Item> items = (ArrayList<Item>) bag.items.clone();
for(Item i : bag.items){
if (Dungeon.hero.belongings.lostInventory() && !i.keptThroughLostInventory()) items.remove(i);
if (!Recipe.usableInRecipe(i)) items.remove(i);
}
if (items.size() == 0){
ShatteredPixelDungeon.scene().addToFront(new WndMessage(Messages.get(AlchemyScene.class, "no_items")));
return;
}
String[] itemNames = new String[items.size()];
Image[] itemIcons = new Image[items.size()];
for (int i = 0; i < items.size(); i++){
itemNames[i] = Messages.titleCase(items.get(i).name());
itemIcons[i] = new ItemSprite(items.get(i));
}
String info = "";
if (ControllerHandler.controllerActive){
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.LEFT_CLICK, true)) + ": " + Messages.get(Toolbar.class, "item_select") + "\n";
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.BACK, true)) + ": " + Messages.get(Toolbar.class, "item_cancel");
} else {
info += Messages.get(WndKeyBindings.class, SPDAction.LEFT_CLICK.name()) + ": " + Messages.get(Toolbar.class, "item_select") + "\n";
info += KeyBindings.getKeyName(KeyBindings.getFirstKeyForAction(GameAction.BACK, false)) + ": " + Messages.get(Toolbar.class, "item_cancel");
}
Game.scene().addToFront(new RadialMenu(Messages.get(Toolbar.class, "item_prompt"), info, itemNames, itemIcons){
@Override
public void onSelect(int idx, boolean alt) {
super.onSelect(idx, alt);
Item item = items.get(idx);
synchronized (inputs) {
if (item != null && inputs[0] != null) {
for (int i = 0; i < inputs.length; i++) {
if (inputs[i].item() == null) {
if (item instanceof LiquidMetal){
inputs[i].item(item.detachAll(Dungeon.hero.belongings.backpack));
} else {
inputs[i].item(item.detach(Dungeon.hero.belongings.backpack));
}
break;
}
}
updateState();
}
}
}
});
}
});
}
}
@Override
public GameAction keyAction() {
return SPDAction.INVENTORY_SELECTOR;
}
};
add(invSelector);
cancel = new IconButton(Icons.CLOSE.get()){
@Override
protected void onClick() {
super.onClick();
clearSlots();
updateState();
}
@Override
public GameAction keyAction() {
return SPDAction.BACK;
}
@Override
protected String hoverText() {
return Messages.get(AlchemyScene.class, "cancel");
}
};
cancel.setRect(left + 8, pos + 2, 16, 16);
cancel.enable(false);
add(cancel);
repeat = new IconButton(Icons.REPEAT.get()){
@Override
protected void onClick() {
super.onClick();
if (lastRecipe != null){
populate(lastIngredients, Dungeon.hero.belongings);
}
}
@Override
public GameAction keyAction() {
return SPDAction.TAG_RESUME;
}
@Override
protected String hoverText() {
return Messages.get(AlchemyScene.class, "repeat");
}
};
repeat.setRect(left + 24, pos + 2, 16, 16);
repeat.enable(false);
add(repeat);
lastIngredients.clear();
lastRecipe = null;
for (int i = 0; i < inputs.length; i++){
combines[i] = new CombineButton(i);
combines[i].enable(false);
@@ -197,16 +358,7 @@ public class AlchemyScene extends PixelScene {
lowerBubbles.pos(0, pos, Camera.main.width, Math.max(0, Camera.main.height-pos));
lowerBubbles.pour(Speck.factory( Speck.BUBBLE ), 0.1f );
ExitButton btnExit = new ExitButton(){
@Override
protected void onClick() {
Game.switchScene(GameScene.class);
}
};
btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
add( btnExit );
IconButton btnGuide = new IconButton( new ItemSprite(ItemSpriteSheet.ALCH_PAGE, null)){
@Override
protected void onClick() {
@@ -231,6 +383,11 @@ public class AlchemyScene extends PixelScene {
});
}
@Override
public GameAction keyAction() {
return SPDAction.JOURNAL;
}
@Override
protected String hoverText() {
return Messages.titleCase(Document.ALCHEMY_GUIDE.title());
@@ -263,6 +420,16 @@ public class AlchemyScene extends PixelScene {
protected void onClick() {
WndEnergizeItem.openItemSelector();
}
@Override
public GameAction keyAction() {
return SPDAction.TAG_ACTION;
}
@Override
protected String hoverText() {
return Messages.get(AlchemyScene.class, "energize");
}
};
energyAdd.setRect(energyLeft.right(), energyLeft.top() - (16 - energyLeft.height())/2, 16, 16);
align(energyAdd);
@@ -339,7 +506,9 @@ public class AlchemyScene extends PixelScene {
}
private void updateState(){
repeat.enable(false);
ArrayList<Item> ingredients = filterInput(Item.class);
ArrayList<Recipe> recipes = Recipe.findRecipes(ingredients);
@@ -354,6 +523,8 @@ public class AlchemyScene extends PixelScene {
}
}
cancel.enable(!ingredients.isEmpty());
if (recipes.isEmpty()){
combines[0].setPos(combines[0].left(), inputs[1].top()+5);
outputs[0].setPos(outputs[0].left(), inputs[1].top());
@@ -397,6 +568,11 @@ public class AlchemyScene extends PixelScene {
ArrayList<Item> ingredients = filterInput(Item.class);
if (ingredients.isEmpty()) return;
lastIngredients.clear();
for (Item i : ingredients){
lastIngredients.add(i.duplicate());
}
ArrayList<Recipe> recipes = Recipe.findRecipes(ingredients);
if (recipes.size() <= slot) return;
@@ -467,7 +643,19 @@ public class AlchemyScene extends PixelScene {
result.quantity(resultQuantity);
outputs[0].item(result);
}
boolean foundItems = true;
for (Item i : lastIngredients){
Item found = Dungeon.hero.belongings.getSimilar(i);
if (found == null){ //atm no quantity check as items are always loaded individually
//currently found can be true if we need, say, 3x of an item but only have 2x of it
foundItems = false;
}
}
lastRecipe = recipe;
repeat.enable(foundItems);
cancel.enable(false);
}
public void populate(ArrayList<Item> toFind, Belongings inventory){
@@ -526,6 +714,8 @@ public class AlchemyScene extends PixelScene {
}
}
}
cancel.enable(false);
repeat.enable(lastRecipe != null);
}
public void createEnergy(){
@@ -599,6 +789,34 @@ public class AlchemyScene extends PixelScene {
}
return false;
}
@Override
//only the first empty button accepts key input
public GameAction keyAction() {
for (InputButton i : inputs){
if (i.item == null || i.item instanceof WndBag.Placeholder) {
if (i == InputButton.this) {
return SPDAction.INVENTORY;
} else {
return super.keyAction();
}
}
}
return super.keyAction();
}
@Override
protected String hoverText() {
if (item == null || item instanceof WndBag.Placeholder){
return Messages.get(AlchemyScene.class, "add");
}
return super.hoverText();
}
@Override
public GameAction secondaryTooltipAction() {
return SPDAction.INVENTORY_SELECTOR;
}
};
slot.enable(true);
add( slot );
@@ -652,6 +870,19 @@ public class AlchemyScene extends PixelScene {
super.onClick();
combine(slot);
}
@Override
protected String hoverText() {
return "Craft";
}
@Override
public GameAction keyAction() {
if (slot == 0 && !combines[1].active && !combines[2].active){
return SPDAction.TAG_LOOT;
}
return super.keyAction();
}
};
button.icon(Icons.get(Icons.ARROW));
add(button);
@@ -696,6 +927,7 @@ public class AlchemyScene extends PixelScene {
}
layout();
active = enabled;
}
}