v0.7.0: completely overhauled the alchemy guidebook interface

This commit is contained in:
Evan Debenham 2018-10-04 22:02:34 -04:00
parent 6e3097724a
commit e5867c8dd4
11 changed files with 634 additions and 93 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -58,6 +58,7 @@ import com.watabou.utils.Random;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class Bomb extends Item {
@ -305,34 +306,38 @@ public class Bomb extends Item {
public static class EnhanceBomb extends Recipe {
private static final HashMap<Class<?extends Item>, Class<?extends Bomb>> validIngredients = new HashMap<>();
public static final LinkedHashMap<Class<?extends Item>, Class<?extends Bomb>> validIngredients = new LinkedHashMap<>();
static {
validIngredients.put(PotionOfLiquidFlame.class, Firebomb.class);
validIngredients.put(PotionOfFrost.class, FrostBomb.class);
validIngredients.put(PotionOfHealing.class, RegrowthBomb.class);
validIngredients.put(PotionOfInvisibility.class, Flashbang.class);
validIngredients.put(ScrollOfRecharging.class, ShockBomb.class);
validIngredients.put(ScrollOfRemoveCurse.class, HolyBomb.class);
validIngredients.put(ScrollOfMirrorImage.class, WoollyBomb.class);
validIngredients.put(PotionOfLiquidFlame.class, Firebomb.class);
validIngredients.put(ScrollOfRage.class, Noisemaker.class);
validIngredients.put(PotionOfInvisibility.class, Flashbang.class);
validIngredients.put(ScrollOfRecharging.class, ShockBomb.class);
validIngredients.put(PotionOfHealing.class, RegrowthBomb.class);
validIngredients.put(ScrollOfRemoveCurse.class, HolyBomb.class);
validIngredients.put(GooBlob.class, ArcaneBomb.class);
validIngredients.put(MetalShard.class, ShrapnelBomb.class);
}
private static final HashMap<Class<?extends Bomb>, Integer> bombCosts = new HashMap<>();
static {
bombCosts.put(Firebomb.class, 4);
bombCosts.put(FrostBomb.class, 3);
bombCosts.put(RegrowthBomb.class, 6);
bombCosts.put(Flashbang.class, 5);
bombCosts.put(ShockBomb.class, 5);
bombCosts.put(HolyBomb.class, 6);
bombCosts.put(WoollyBomb.class, 3);
bombCosts.put(Firebomb.class, 4);
bombCosts.put(Noisemaker.class, 4);
bombCosts.put(Flashbang.class, 5);
bombCosts.put(ShockBomb.class, 5);
bombCosts.put(RegrowthBomb.class, 6);
bombCosts.put(HolyBomb.class, 6);
bombCosts.put(ArcaneBomb.class, 8);
bombCosts.put(ShrapnelBomb.class, 8);
}

View File

@ -76,7 +76,7 @@ public class MysteryMeat extends Food {
public static class PlaceHolder extends MysteryMeat {
{
image = ItemSpriteSheet.MEAT_HOLDER;
image = ItemSpriteSheet.FOOD_HOLDER;
}
@Override

View File

@ -59,6 +59,10 @@ public enum Document {
return pages.containsKey(page) && pages.get(page);
}
public boolean hasPage( int pageIdx ){
return hasPage( pages.keySet().toArray(new String[0])[pageIdx] );
}
public boolean hasAnyPages(){
for (String p : pages.keySet()){
if (pages.get(p)) {
@ -81,10 +85,18 @@ public enum Document {
return Messages.get( this, name() + "." + page + ".title");
}
public String pageTitle( int pageIdx ){
return pageTitle( pages.keySet().toArray(new String[0])[pageIdx] );
}
public String pageBody( String page ){
return Messages.get( this, name() + "." + page + ".body");
}
public String pageBody( int pageIdx ){
return pageBody( pages.keySet().toArray(new String[0])[pageIdx] );
}
public static final String GUIDE_INTRO_PAGE = "Intro";
public static final String GUIDE_SEARCH_PAGE = "Examining_and_Searching";
@ -103,17 +115,13 @@ public enum Document {
ALCHEMY_GUIDE.pages.put("Potions", false);
ALCHEMY_GUIDE.pages.put("Stones", false);
ALCHEMY_GUIDE.pages.put("Darts", false);
ALCHEMY_GUIDE.pages.put("Exotics", false);
ALCHEMY_GUIDE.pages.put("Energy", false);
ALCHEMY_GUIDE.pages.put("Food", false);
ALCHEMY_GUIDE.pages.put("Exotic_Potions", false);
ALCHEMY_GUIDE.pages.put("Exotic_Scrolls", false);
ALCHEMY_GUIDE.pages.put("Energy_Food", false);
ALCHEMY_GUIDE.pages.put("Bombs", false);
ALCHEMY_GUIDE.pages.put("Combo_Brews", false);
ALCHEMY_GUIDE.pages.put("Heal_Elixirs", false);
ALCHEMY_GUIDE.pages.put("AOE_Brews", false);
ALCHEMY_GUIDE.pages.put("Imbue_Elixirs", false);
ALCHEMY_GUIDE.pages.put("Tele_Spells", false);
ALCHEMY_GUIDE.pages.put("Item_Spells", false);
ALCHEMY_GUIDE.pages.put("Enviro_Spells", false);
ALCHEMY_GUIDE.pages.put("Brews", false);
ALCHEMY_GUIDE.pages.put("Elixirs", false);
ALCHEMY_GUIDE.pages.put("Spells", false);
}
private static final String DOCUMENTS = "documents";

View File

@ -84,9 +84,8 @@ public class LaboratoryRoom extends SpecialRoom {
}
}
//drops a page every room for now
//TODO make pages rarer as players get more, once more alchemy comes out
if(!missingPages.isEmpty()){
//pages after 5 are always deeper than the sewers
if(!missingPages.isEmpty() && (missingPages.size() > 5 || Dungeon.depth > 5)){
AlchemyPage p = new AlchemyPage();
p.page(missingPages.get(0));
int pos;

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.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
@ -32,7 +33,6 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Recipe;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.AlchemistsToolkit;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.Dart;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
@ -45,8 +45,8 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextMultiline;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndDocument;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoItem;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndJournal;
import com.watabou.gltextures.TextureCache;
import com.watabou.glwrap.Blending;
import com.watabou.noosa.Camera;
@ -250,7 +250,23 @@ public class AlchemyScene extends PixelScene {
@Override
protected void onClick() {
super.onClick();
AlchemyScene.this.addToFront(new WndDocument(Document.ALCHEMY_GUIDE));
clearSlots();
updateState();
AlchemyScene.this.addToFront(new Window(){
{
WndJournal.AlchemyTab t = new WndJournal.AlchemyTab();
if (SPDSettings.landscape()) {
resize(200, 130);
t.setRect(0, 0, 200, 130);
} else {
resize(130, 180);
t.setRect(0, 0, 130, 180);
}
add(t);
}
});
}
};
btnGuide.setRect(0, 0, 16, 16);
@ -450,6 +466,8 @@ public class AlchemyScene extends PixelScene {
Dungeon.level.drop(inputs[i].item, Dungeon.hero.pos);
}
}
inputs[i].item(null);
inputs[i].slot.item(new WndBag.Placeholder(ItemSpriteSheet.SOMETHING));
}
}
}

View File

@ -81,6 +81,10 @@ public class ItemSprite extends MovieClip {
view (item);
}
public ItemSprite( int image ){
this( image, null );
}
public ItemSprite( int image, Glowing glowing ) {
super( Assets.ITEMS );

View File

@ -36,32 +36,40 @@ public class ItemSpriteSheet {
}
private static final int PLACEHOLDERS = xy(1, 1); //16 slots
//null warning occupies space 0, should only show up if there's a bug.
public static final int NULLWARN = PLACEHOLDERS+0;
//SOMETHING is the default item sprite at position 0. May show up ingame if there are bugs.
public static final int SOMETHING = PLACEHOLDERS+0;
public static final int WEAPON_HOLDER = PLACEHOLDERS+1;
public static final int ARMOR_HOLDER = PLACEHOLDERS+2;
public static final int WAND_HOLDER = PLACEHOLDERS+3;
public static final int RING_HOLDER = PLACEHOLDERS+4;
public static final int ARTIFACT_HOLDER = PLACEHOLDERS+5;
public static final int POTION_HOLDER = PLACEHOLDERS+6;
public static final int SCROLL_HOLDER = PLACEHOLDERS+7;
public static final int SEED_HOLDER = PLACEHOLDERS+8;
public static final int STONE_HOLDER = PLACEHOLDERS+9;
public static final int MEAT_HOLDER = PLACEHOLDERS+10;
public static final int SOMETHING = PLACEHOLDERS+11;
public static final int MISSILE_HOLDER = PLACEHOLDERS+3;
public static final int WAND_HOLDER = PLACEHOLDERS+4;
public static final int RING_HOLDER = PLACEHOLDERS+5;
public static final int ARTIFACT_HOLDER = PLACEHOLDERS+6;
public static final int FOOD_HOLDER = PLACEHOLDERS+7;
public static final int BOMB_HOLDER = PLACEHOLDERS+8;
public static final int POTION_HOLDER = PLACEHOLDERS+9;
public static final int SCROLL_HOLDER = PLACEHOLDERS+11;
public static final int SEED_HOLDER = PLACEHOLDERS+10;
public static final int STONE_HOLDER = PLACEHOLDERS+12;
public static final int BREW_HOLDER = PLACEHOLDERS+13;
public static final int ELIXIR_HOLDER = PLACEHOLDERS+14;
public static final int SPELL_HOLDER = PLACEHOLDERS+15;
static{
assignItemRect(NULLWARN, 16, 7);
assignItemRect(SOMETHING, 8, 13);
assignItemRect(WEAPON_HOLDER, 14, 14);
assignItemRect(ARMOR_HOLDER, 14, 12);
assignItemRect(MISSILE_HOLDER, 15, 15);
assignItemRect(WAND_HOLDER, 14, 14);
assignItemRect(RING_HOLDER, 8, 10);
assignItemRect(ARTIFACT_HOLDER, 15, 15);
assignItemRect(FOOD_HOLDER, 15, 11);
assignItemRect(BOMB_HOLDER, 10, 13);
assignItemRect(POTION_HOLDER, 12, 14);
assignItemRect(SCROLL_HOLDER, 15, 14);
assignItemRect(SEED_HOLDER, 10, 10);
assignItemRect(SCROLL_HOLDER, 15, 14);
assignItemRect(STONE_HOLDER, 14, 12);
assignItemRect(MEAT_HOLDER, 15, 11);
assignItemRect(SOMETHING, 8, 13);
assignItemRect(BREW_HOLDER, 10, 14);
assignItemRect(ELIXIR_HOLDER, 10, 14);
assignItemRect(SPELL_HOLDER, 8, 16);
}
private static final int UNCOLLECTIBLE = xy(1, 2); //16 slots

View File

@ -0,0 +1,370 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2018 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 <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.ui;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.Recipe;
import com.shatteredpixel.shatteredpixeldungeon.items.bombs.Bomb;
import com.shatteredpixel.shatteredpixeldungeon.items.food.Blandfruit;
import com.shatteredpixel.shatteredpixeldungeon.items.food.Feast;
import com.shatteredpixel.shatteredpixeldungeon.items.food.Food;
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
import com.shatteredpixel.shatteredpixeldungeon.items.food.Pasty;
import com.shatteredpixel.shatteredpixeldungeon.items.food.StewedMeat;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.BlizzardBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.CausticBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.FrigidBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.FrostfireBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.InfernalBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.ShockingBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.brews.WickedBrew;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfAquaticRejuvenation;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfDragonsBlood;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfHoneyedHealing;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfIcyTouch;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfRestoration;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfToxicEssence;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfVitality;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic.ExoticPotion;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ExoticScroll;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.Alchemize;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.AquaBlast;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.BeaconOfReturning;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.CurseInfusion;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.FeatherFall;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.MagicalInfusion;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.MagicalPorter;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.PhaseShift;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.ReclaimTrap;
import com.shatteredpixel.shatteredpixeldungeon.items.spells.Recycle;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.Runestone;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.Dart;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.TippedDart;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.scenes.AlchemyScene;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoItem;
import com.watabou.noosa.BitmapText;
import com.watabou.noosa.Group;
import com.watabou.noosa.Image;
import com.watabou.noosa.ui.Component;
import java.util.ArrayList;
import java.util.Arrays;
public class QuickRecipe extends Component {
private ArrayList<Item> ingredients;
private ArrayList<ItemSlot> inputs;
private QuickRecipe.arrow arrow;
private ItemSlot output;
public QuickRecipe(Recipe.SimpleRecipe r){
this(r, r.getIngredients(), r.sampleOutput(null));
}
public QuickRecipe(Recipe r, ArrayList<Item> inputs, final Item output) {
ingredients = inputs;
int cost = r.cost(inputs);
boolean hasInputs = true;
this.inputs = new ArrayList<>();
for (final Item in : inputs) {
anonymize(in);
ItemSlot curr;
curr = new ItemSlot(in) {
@Override
protected void onClick() {
ShatteredPixelDungeon.scene().addToFront(new WndInfoItem(in));
}
};
ArrayList<Item> similar = Dungeon.hero.belongings.getAllSimilar(in);
int quantity = 0;
for (Item sim : similar) {
if (sim.isIdentified()) quantity += sim.quantity();
}
if (quantity < in.quantity()) {
curr.icon.alpha(0.3f);
hasInputs = false;
}
curr.showParams(true, false, true);
add(curr);
this.inputs.add(curr);
}
if (cost > 0) {
arrow = new arrow(Icons.get(Icons.RESUME), cost);
arrow.hardlightText(0x00CCFF);
} else {
arrow = new arrow(Icons.get(Icons.RESUME));
}
if (hasInputs) {
arrow.icon.tint(1, 1, 0, 1);
if (!(ShatteredPixelDungeon.scene() instanceof AlchemyScene)) {
arrow.enable(false);
}
} else {
arrow.icon.color(0, 0, 0);
arrow.enable(false);
}
add(arrow);
anonymize(output);
this.output = new ItemSlot(output){
@Override
protected void onClick() {
ShatteredPixelDungeon.scene().addToFront(new WndInfoItem(output));
}
};
this.output.showParams(true, false, true);
add(this.output);
layout();
}
@Override
protected void layout() {
height = 16;
width = 0;
for (ItemSlot item : inputs){
item.setRect(x + width, y, 16, 16);
width += 16;
}
arrow.setRect(x + width, y, 14, 16);
width += 14;
output.setRect(x + width, y, 16, 16);
width += 16;
}
//used to ensure that un-IDed items are not spoiled
private void anonymize(Item item){
if (item instanceof Potion){
((Potion) item).anonymize();
} else if (item instanceof Scroll){
((Scroll) item).anonymize();
}
}
public class arrow extends IconButton {
BitmapText text;
public arrow(){
super();
}
public arrow( Image icon ){
super( icon );
}
public arrow( Image icon, int count ){
super( icon );
text = new BitmapText( Integer.toString(count), PixelScene.pixelFont);
text.measure();
add(text);
}
@Override
protected void layout() {
super.layout();
if (text != null){
text.x = x;
text.y = y;
PixelScene.align(text);
}
}
@Override
protected void onClick() {
super.onClick();
//find the window this is inside of and close it
Group parent = this.parent;
while (parent != null){
if (parent instanceof Window){
((Window) parent).hide();
break;
} else {
parent = parent.parent;
}
}
((AlchemyScene)ShatteredPixelDungeon.scene()).populate(ingredients, Dungeon.hero.belongings);
}
public void hardlightText(int color ){
if (text != null) text.hardlight(color);
}
}
//gets recipes for a particular alchemy guide page
//a null entry indicates a break in section
public static ArrayList<QuickRecipe> getRecipes( int pageIdx ){
ArrayList<QuickRecipe> result = new ArrayList<>();
switch (pageIdx){
case 0: default:
result.add(new QuickRecipe( new Potion.SeedToPotion(), new ArrayList<>(Arrays.asList(new Plant.Seed.PlaceHolder().quantity(3))), new WndBag.Placeholder(ItemSpriteSheet.POTION_HOLDER){
{
name = Messages.get(Potion.SeedToPotion.class, "name");
}
@Override
public String info() {
return "";
}
}));
return result;
case 1:
Recipe r = new Scroll.ScrollToStone();
for (Class<?> cls : Generator.Category.SCROLL.classes){
try{
Scroll scroll = (Scroll) cls.newInstance();
ArrayList<Item> in = new ArrayList<Item>(Arrays.asList(scroll));
result.add(new QuickRecipe( r, in, r.sampleOutput(in)));
} catch (Exception e){
ShatteredPixelDungeon.reportException(e);
}
}
return result;
case 2:
r = new TippedDart.TipDart();
for (Class<?> cls : Generator.Category.SEED.classes){
try{
Plant.Seed seed = (Plant.Seed) cls.newInstance();
ArrayList<Item> in = new ArrayList<>(Arrays.asList(seed, new Dart()));
result.add(new QuickRecipe( r, in, r.sampleOutput(in)));
} catch (Exception e){
ShatteredPixelDungeon.reportException(e);
}
}
return result;
case 3:
r = new ExoticPotion.PotionToExotic();
for (Class<?> cls : Generator.Category.POTION.classes){
try{
Potion pot = (Potion) cls.newInstance();
ArrayList<Item> in = new ArrayList<>(Arrays.asList(pot, new Plant.Seed.PlaceHolder().quantity(2)));
result.add(new QuickRecipe( r, in, r.sampleOutput(in)));
} catch (Exception e){
ShatteredPixelDungeon.reportException(e);
}
}
return result;
case 4:
r = new ExoticScroll.ScrollToExotic();
for (Class<?> cls : Generator.Category.SCROLL.classes){
try{
Scroll scroll = (Scroll) cls.newInstance();
ArrayList<Item> in = new ArrayList<>(Arrays.asList(scroll, new Runestone.PlaceHolder().quantity(2)));
result.add(new QuickRecipe( r, in, r.sampleOutput(in)));
} catch (Exception e){
ShatteredPixelDungeon.reportException(e);
}
}
return result;
case 5:
result.add(new QuickRecipe( new StewedMeat.oneMeat() ));
result.add(new QuickRecipe( new StewedMeat.twoMeat() ));
result.add(new QuickRecipe( new StewedMeat.threeMeat() ));
result.add(null);
result.add(new QuickRecipe( new Feast.Recipe(),
new ArrayList<Item>(Arrays.asList(new Pasty(), new Food(), new MysteryMeat.PlaceHolder())),
new Feast()));
result.add(new QuickRecipe( new Blandfruit.CookFruit(),
new ArrayList<>(Arrays.asList(new Blandfruit(), new Plant.Seed.PlaceHolder())),
new Blandfruit(){
{
name = "Cooked Blandfruit";
}
@Override
public String info() {
return "";
}
})); //TODO
return result;
case 6:
r = new Bomb.EnhanceBomb();
for (Class<?> cls : Bomb.EnhanceBomb.validIngredients.keySet()){
try{
Item item = (Item) cls.newInstance();
ArrayList<Item> in = new ArrayList<Item>(Arrays.asList(new Bomb(), item));
result.add(new QuickRecipe( r, in, r.sampleOutput(in)));
} catch (Exception e){
ShatteredPixelDungeon.reportException(e);
}
}
return result;
case 7:
result.add(new QuickRecipe(new WickedBrew.Recipe()));
result.add(new QuickRecipe(new FrigidBrew.Recipe()));
result.add(new QuickRecipe(new FrostfireBrew.Recipe()));
result.add(new QuickRecipe(new CausticBrew.Recipe()));
result.add(null);
result.add(new QuickRecipe(new InfernalBrew.Recipe()));
result.add(new QuickRecipe(new BlizzardBrew.Recipe()));
result.add(new QuickRecipe(new ShockingBrew.Recipe()));
return result;
case 8:
result.add(new QuickRecipe(new ElixirOfRestoration.Recipe()));
result.add(new QuickRecipe(new ElixirOfVitality.Recipe()));
result.add(new QuickRecipe(new ElixirOfHoneyedHealing.Recipe()));
result.add(new QuickRecipe(new ElixirOfAquaticRejuvenation.Recipe()));
result.add(null);
result.add(new QuickRecipe(new ElixirOfDragonsBlood.Recipe()));
result.add(new QuickRecipe(new ElixirOfIcyTouch.Recipe()));
result.add(new QuickRecipe(new ElixirOfToxicEssence.Recipe()));
return result;
case 9:
result.add(new QuickRecipe(new MagicalPorter.Recipe()));
result.add(new QuickRecipe(new PhaseShift.Recipe()));
result.add(new QuickRecipe(new BeaconOfReturning.Recipe()));
result.add(null);
result.add(new QuickRecipe(new AquaBlast.Recipe()));
result.add(new QuickRecipe(new FeatherFall.Recipe()));
result.add(new QuickRecipe(new ReclaimTrap.Recipe()));
result.add(null);
result.add(new QuickRecipe(new MagicalInfusion.Recipe()));
result.add(new QuickRecipe(new CurseInfusion.Recipe()));
result.add(new QuickRecipe(new Alchemize.Recipe()));
result.add(new QuickRecipe(new Recycle.Recipe()));
return result;
}
}
}

View File

@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.QuickRecipe;
import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextMultiline;
import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane;
@ -53,15 +54,16 @@ import java.util.HashMap;
//FIXME a lot of cleanup and improvements to do here
public class WndJournal extends WndTabbed {
private static final int WIDTH_P = 120;
private static final int HEIGHT_P = 160;
private static final int WIDTH_P = 130;
private static final int HEIGHT_P = 180;
private static final int WIDTH_L = 160;
private static final int HEIGHT_L = 128;
private static final int WIDTH_L = 200;
private static final int HEIGHT_L = 130;
private static final int ITEM_HEIGHT = 18;
private GuideTab guideTab;
private AlchemyTab alchemyTab;
private NotesTab notesTab;
private CatalogTab catalogTab;
@ -79,6 +81,10 @@ public class WndJournal extends WndTabbed {
guideTab.setRect(0, 0, width, height);
guideTab.updateList();
alchemyTab = new AlchemyTab();
add(alchemyTab);
alchemyTab.setRect(0, 0, width, height);
notesTab = new NotesTab();
add(notesTab);
notesTab.setRect(0, 0, width, height);
@ -97,18 +103,25 @@ public class WndJournal extends WndTabbed {
if (value) last_index = 0;
}
},
new IconTab( new ItemSprite(ItemSpriteSheet.ALCH_PAGE, null) ) {
protected void select( boolean value ) {
super.select( value );
alchemyTab.active = alchemyTab.visible = value;
if (value) last_index = 1;
}
},
new IconTab( Icons.get(Icons.DEPTH) ) {
protected void select( boolean value ) {
super.select( value );
notesTab.active = notesTab.visible = value;
if (value) last_index = 1;
if (value) last_index = 2;
}
},
new IconTab( new ItemSprite(ItemSpriteSheet.WEAPON_HOLDER, null) ) {
protected void select( boolean value ) {
super.select( value );
catalogTab.active = catalogTab.visible = value;
if (value) last_index = 2;
if (value) last_index = 3;
}
}
};
@ -223,7 +236,7 @@ public class WndJournal extends WndTabbed {
line.y = pos;
content.add(line);
RenderedTextMultiline title = PixelScene.renderMultiline(Messages.get(this, "title"), 9);
RenderedTextMultiline title = PixelScene.renderMultiline(Document.ADVENTURERS_GUIDE.title(), 9);
title.hardlight(TITLE_COLOR);
title.maxWidth( (int)width() - 2 );
title.setPos( (width() - title.width())/2f, pos + 1 + ((ITEM_HEIGHT) - title.height())/2f);
@ -232,8 +245,8 @@ public class WndJournal extends WndTabbed {
pos += Math.max(ITEM_HEIGHT, title.height());
for (Document doc : Document.values()){
GuideItem item = new GuideItem( doc );
for (String page : Document.ADVENTURERS_GUIDE.pages()){
GuideItem item = new GuideItem( page );
item.setRect( 0, pos, width(), ITEM_HEIGHT );
content.add( item );
@ -249,18 +262,18 @@ public class WndJournal extends WndTabbed {
private static class GuideItem extends ListItem {
private boolean found = false;
private Document doc;
private String page;
public GuideItem( Document doc ){
super( new ItemSprite( doc.pageSprite(), null),
Messages.titleCase( doc.title() ), -1);
public GuideItem( String page ){
super( new ItemSprite( ItemSpriteSheet.GUIDE_PAGE, null),
Messages.titleCase(Document.ADVENTURERS_GUIDE.pageTitle(page)), -1);
this.doc = doc;
found = doc.hasAnyPages();
this.page = page;
found = Document.ADVENTURERS_GUIDE.hasPage(page);
if (!found) {
icon.hardlight( 0.5f, 0.5f, 0.5f);
label.text( Messages.titleCase( "???" ));
label.text( Messages.titleCase(Messages.get( this, "missing" )));
label.hardlight( 0x999999 );
}
@ -268,7 +281,7 @@ public class WndJournal extends WndTabbed {
public boolean onClick( float x, float y ) {
if (inside( x, y ) && found) {
GameScene.show( new WndDocument(doc));
GameScene.show( new WndStory( Document.ADVENTURERS_GUIDE.pageBody(page) ));
return true;
} else {
return false;
@ -279,6 +292,129 @@ public class WndJournal extends WndTabbed {
}
public static class AlchemyTab extends Component {
private RedButton[] pageButtons;
private static final int NUM_BUTTONS = 10;
private static final int spriteIndexes[] = {10, 12, 3, 9, 11, 7, 8, 13, 14, 15};
private static int currentPageIdx = -1;
private IconTitle title;
private RenderedTextMultiline body;
private ArrayList<QuickRecipe> recipes = new ArrayList<>();
@Override
protected void createChildren() {
pageButtons = new RedButton[NUM_BUTTONS];
for (int i = 0; i < NUM_BUTTONS; i++){
final int idx = i;
pageButtons[i] = new RedButton( "" ){
@Override
protected void onClick() {
currentPageIdx = idx;
updateList();
}
};
if (Document.ALCHEMY_GUIDE.hasPage(i)) {
pageButtons[i].icon(new ItemSprite(ItemSpriteSheet.SOMETHING + spriteIndexes[i], null));
} else {
pageButtons[i].icon(new ItemSprite(ItemSpriteSheet.SOMETHING, null));
pageButtons[i].enable(false);
}
add( pageButtons[i] );
}
title = new IconTitle();
title.icon( new ItemSprite(ItemSpriteSheet.ALCH_PAGE));
title.visible = false;
add(title);
body = PixelScene.renderMultiline(6);
add(body);
}
@Override
protected void layout() {
super.layout();
int perRow = NUM_BUTTONS / (SPDSettings.landscape() ? 1 : 2);
float buttonWidth = width()/perRow;
for (int i = 0; i < NUM_BUTTONS; i++) {
pageButtons[i].setRect((i%perRow) * (buttonWidth), (i/perRow) * (ITEM_HEIGHT),
buttonWidth, ITEM_HEIGHT);
PixelScene.align(pageButtons[i]);
}
updateList();
}
private void updateList() {
for (int i = 0; i < NUM_BUTTONS; i++) {
if (i == currentPageIdx) {
pageButtons[i].icon().color(TITLE_COLOR);
} else {
pageButtons[i].icon().resetColor();
}
}
if (currentPageIdx == -1){
return;
}
title.visible = true;
title.label(Document.ALCHEMY_GUIDE.pageTitle(currentPageIdx));
title.setRect(0, pageButtons[NUM_BUTTONS-1].bottom(), width(), 10);
body.maxWidth((int)width());
body.text(Document.ALCHEMY_GUIDE.pageBody(currentPageIdx));
body.setPos(0, title.bottom());
for (QuickRecipe r : recipes){
if (r != null) {
r.killAndErase();
r.destroy();
}
}
recipes.clear();
ArrayList<QuickRecipe> toAdd = QuickRecipe.getRecipes(currentPageIdx);
float left;
float top = body.bottom() + 2;
int w;
ArrayList<QuickRecipe> toAddThisRow = new ArrayList<>();
while (!toAdd.isEmpty()){
while (!toAdd.isEmpty() && toAdd.get(0) == null){
top += 2;
toAdd.remove(0);
}
w = 0;
while(!toAdd.isEmpty() && toAdd.get(0) != null
&& w + toAdd.get(0).width() <= width()){
toAddThisRow.add(toAdd.remove(0));
w += toAddThisRow.get(0).width();
}
float spacing = (width() - w)/(toAddThisRow.size() + 1);
left = spacing;
for (QuickRecipe r : toAddThisRow){
r.setPos(left, top);
left += r.width() + spacing;
recipes.add(r);
add(r);
}
top += 17;
toAddThisRow.clear();
}
}
}
private static class NotesTab extends Component {
private ScrollPane list;
@ -363,6 +499,7 @@ public class WndJournal extends WndTabbed {
private static int currentItemIdx = 0;
//sprite locations
private static final int WEAPON_IDX = 0;
private static final int ARMOR_IDX = 1;
private static final int WAND_IDX = 2;
@ -371,6 +508,8 @@ public class WndJournal extends WndTabbed {
private static final int POTION_IDX = 5;
private static final int SCROLL_IDX = 6;
private static final int spriteIndexes[] = {1, 2, 4, 5, 6, 9, 11};
private ScrollPane list;
private ArrayList<CatalogItem> items = new ArrayList<>();
@ -387,7 +526,7 @@ public class WndJournal extends WndTabbed {
updateList();
}
};
itemButtons[i].icon(new ItemSprite(ItemSpriteSheet.WEAPON_HOLDER + i, null));
itemButtons[i].icon(new ItemSprite(ItemSpriteSheet.SOMETHING + spriteIndexes[i], null));
add( itemButtons[i] );
}
@ -405,8 +544,6 @@ public class WndJournal extends WndTabbed {
add( list );
}
private static final int BUTTON_HEIGHT = 17;
@Override
protected void layout() {
super.layout();
@ -415,8 +552,8 @@ public class WndJournal extends WndTabbed {
float buttonWidth = width()/perRow;
for (int i = 0; i < NUM_BUTTONS; i++) {
itemButtons[i].setRect((i%perRow) * (buttonWidth), (i/perRow) * (BUTTON_HEIGHT + 1),
buttonWidth, BUTTON_HEIGHT);
itemButtons[i].setRect((i%perRow) * (buttonWidth), (i/perRow) * (ITEM_HEIGHT ),
buttonWidth, ITEM_HEIGHT);
PixelScene.align(itemButtons[i]);
}
@ -512,11 +649,11 @@ public class WndJournal extends WndTabbed {
this.seen = seen;
if (!seen) {
icon.copy( new ItemSprite( ItemSpriteSheet.WEAPON_HOLDER + currentItemIdx, null) );
icon.copy( new ItemSprite( ItemSpriteSheet.SOMETHING + spriteIndexes[currentItemIdx], null) );
label.text("???");
label.hardlight( 0x999999 );
} else if (!IDed) {
icon.copy( new ItemSprite( ItemSpriteSheet.WEAPON_HOLDER + currentItemIdx, null) );
icon.copy( new ItemSprite( ItemSpriteSheet.SOMETHING + spriteIndexes[currentItemIdx], null) );
label.hardlight( 0xCCCCCC );
}

View File

@ -22,33 +22,25 @@ journal.document.adventurers_guide.magic.body=Magical attacks cut right through
journal.document.alchemy_guide.title=Alchemy Guide
journal.document.alchemy_guide.potions.title=Creating Potions
journal.document.alchemy_guide.potions.body=Welcome to Practical Applications of Alchemy!\n\nThis book serves as a recipe reference for hobbyist alchemists and adventurers looking to get their hands dirty.\n\nWe will start with the most iconic alchemy recipe: Place any three seeds into an alchemy pot to brew a potion!\n\nEvery seed type has a potion counterpart. The potion you create may relate to one of the seeds used, but there is a chance it will be random as well. Using multiple of the same type of seed will decrease the chance for a random potion.
journal.document.alchemy_guide.potions.body=Welcome to Practical Applications of Alchemy!\n\nThis book serves as a recipe reference for hobbyist alchemists and adventurers looking to get their hands dirty.\n\nWe will start with the most iconic alchemy recipe: Place any three seeds into an alchemy pot to brew a random potion!\n\nEvery seed has a potion counterpart. The potion you create may relate to one of the seeds used, and using multiple of the same seed will increase the chance for this to occur.
journal.document.alchemy_guide.stones.title=Creating Runestones
journal.document.alchemy_guide.stones.body=Mixing a single scroll into an alchemy pot will imbue its magic into two or three rocks within the pot. This creates runestones that correspond to that scroll.\n\nRunestones are a lesser variant of scrolls, just as seeds are a lesser variant of potions. Unlike seeds however, runestones cannot be combined to make a scroll.
journal.document.alchemy_guide.stones.body=Mixing a single scroll into an alchemy pot will imbue its magic into two or three rocks within the pot. This creates runestones that correspond to that scroll.
journal.document.alchemy_guide.darts.title=Tipping Darts
journal.document.alchemy_guide.darts.body=A single seed can be combined with one or two darts to tip them. Each type of seed produces its own type of tipped dart, with a unique effect.\n\nTipped darts only last for one use however, and will revert to regular darts when recovered.
journal.document.alchemy_guide.exotics.title=Exotic Potions and Scrolls
journal.document.alchemy_guide.exotics.body=The power of a potion or scroll can be augmented to create a new 'exotic' variant. These exotic items have more powerful effects, but they are often useful in different ways as well.\n\nCombining a potion and any two seeds will produce an exotic potion. Combining a scroll with any two runestones will produce an exotic scroll.
journal.document.alchemy_guide.energy.title=Alchemical Energy
journal.document.alchemy_guide.energy.body=While the recipes we have discussed so far only need their ingredients, some recipes require energy from the alchemy pot itself. This Energy is a limited resource, but can be used to make recipes that are more than the sum of their ingredients. Some recipes will require a small amount of energy, some require a lot.\n\nAll further recipes discussed in this book will make use of Alchemical Energy.
journal.document.alchemy_guide.food.title=Food Recipes
journal.document.alchemy_guide.food.body=Not all recipes involve magical potions or scrolls, some are more traditional.\n\nRaw meat can be stewed in an alchemy pot, and the pot's energy will cleanse the meat of disease. The more meat that is used at once, the greater the efficiency of the recipe.\n\nA raw blandfruit can be combined with a seed to create a cooked blandfruit. The cooked fruit will emulate whatever potion the seed corresponds to.\n\nA pasty, full ration, and a piece of meat (any type will do) can be combined to create a feast! Feasts provide an unparalleled culinary experience, but cost a fair amount of energy.
journal.document.alchemy_guide.darts.body=A single seed can be combined with one or two darts to tip them. Each type of seed produces its own type of tipped dart, with a unique single-use effect.
journal.document.alchemy_guide.exotic_potions.title=Exotic Potions
journal.document.alchemy_guide.exotic_potions.body=The power of a potion can be augmented with two seeds to create a new 'exotic' variant. They have more powerful effects, but are often useful in different ways as well.
journal.document.alchemy_guide.exotic_scrolls.title=Exotic Scrolls
journal.document.alchemy_guide.exotic_scrolls.body=Exotic scrolls can also be made with two runestones and a scroll. They're generally a bit stronger than exotic potions, but stones are also harder to come by.
journal.document.alchemy_guide.energy_food.title=Energy and Food
journal.document.alchemy_guide.energy_food.body=Some recipes require energy from the alchemy pot itself. Energy is used to make recipes that are more than the sum of their ingredients, but it's a limited resource.\n\nNot all energy recipes are especially mystical however. These recipes more resemble traditional cooking than alchemy.
journal.document.alchemy_guide.bombs.title=Enhanced Bombs
journal.document.alchemy_guide.bombs.body=A standard black powder bomb can be mixed with a specific item to create an enhanced bomb. The amount of energy needed varies by the item used.\n\nThe following items can produce an enhanced bomb:\n- Potion of Liquid Flame\n- Potion of Frost\n- Potion of Healing\n- Potion of Invisibility\n- Scroll of Recharging\n- Scroll of Remove Curse\n- Scroll of Mirror Image\n- Scroll of Rage\n- Blob of Goo\n- Cursed Metal Shard
journal.document.alchemy_guide.combo_brews.title=Combination Brews
journal.document.alchemy_guide.combo_brews.body=Combination brews are the most simple form of brew, combining the effects of two harmful potions into one.\n\n\nA wicked brew is created by mixing a potion of toxic gas with a potion of paralytic gas.\n\nA frigid brew is created by mixing a potion of frost with a potion of storm clouds.\n\nA frostfire brew is created by mixing a potion of liquid flame with a potion of snap freeze.
journal.document.alchemy_guide.heal_elixirs.title=Healing Elixirs
journal.document.alchemy_guide.heal_elixirs.body=Healing elixirs are also quite simple, combining healing and another effect into one item.\n\n\nAn elixir of restoration is created by mixing a potion of healing with a potion of cleansing.\n\nAn elixir of vitality is created by mixing a potion of healing with a potion of shielding.\n\nAn elixir of honeyed healing is created by mixing a potion of healing with a shattered honeypot.\n\nAn elixir of aquatic rejuvenation is created by mixing a potion of healing and a blob of goo.
journal.document.alchemy_guide.aoe_brews.title=Area of Effect Brews
journal.document.alchemy_guide.aoe_brews.body=Area of effect brews spread a harmful effect over a large area. They are more expensive than combination brews, but also more powerful.\n\n\nAn infernal brew is created by mixing a potion of dragon's breath and a potion of liquid flame.\n\nA blizzard brew is created by mixing a potion of snap freeze and a potion of frost.\n\nA shocking brew is created by mixing a potion of paralytic gas and a potion of storm clouds.\n\nA caustic brew is created by mixing a potion of toxic gas and a blob of goo.
journal.document.alchemy_guide.imbue_elixirs.title=Imbuing Elixirs
journal.document.alchemy_guide.imbue_elixirs.body=Imbuing Elixirs will imbue the drinker with a unique power which may be temporary or permanent. They are more expensive than healing elixirs, but also more powerful.\n\n\nAn elixir of dragon's blood is created by mixing a potion of liquid flame and a potion of purity.\n\nAn elixir of toxic essence is created by mixing a potion of toxic gas and a potion of purity.\n\nAn elixir of icy touch is created by mixing a potion of frost and a potion of purity.\n\nAn elixir of might is created by mixing a potion of strength and a large amount of alchemical energy.
journal.document.alchemy_guide.tele_spells.title=Teleportation Spells
journal.document.alchemy_guide.tele_spells.body=Combining certain ingredients in an alchemy pot will cause magical crystals to precipitate out of the water. The energy in these crystals can be channeled to cast spells! Most spells have multiple uses, but the specific amount varies by spell.\n\nTeleportation spells contain magic that changes the positioning of yourself, enemies, or items in various useful ways.\n\n\nMagical porter is created by mixing a scroll of identification with a merchant's beacon.\n\nPhase shift is created by mixing a scroll of teleportation with a scroll of terror.\n\nBeacon of returning is created by mixing a scroll of passage, a scroll of magic mapping, and a lot of alchemical energy.
journal.document.alchemy_guide.item_spells.title=Item Manipulation Spells
journal.document.alchemy_guide.item_spells.body=Item manipulation spells affect the items in your inventory in a variety of different ways.\n\n\nMagical infusion is created by mixing a scroll of upgrade with a stone of enchantment.\n\nCurse infusion is created by mixing a scroll of remove curse with a cursed metal shard.\n\nAlchemize is created by mixing a scroll of recharging with a potion of liquid flame.\n\nRecycle is created by mixing a scroll of transmutation with a scroll of divination.
journal.document.alchemy_guide.enviro_spells.title=Environmental Spells
journal.document.alchemy_guide.enviro_spells.body=Environmental spells give you new ways to change or interact with the terrain of the dungeon.\n\n\nReclaim trap is created by mixing a scroll of recharging with a cursed metal shard.\n\nAqua blast is created by mixing a scroll of identify with a potion of storm clouds.\n\nFeather fall is created by mixing a scroll of lullaby, a potion of levitation, and a good amount of alchemical energy.
journal.document.alchemy_guide.bombs.body=A standard black powder bomb can be mixed with a specific item to create an enhanced bomb. The amount of energy needed varies by the item used.
journal.document.alchemy_guide.brews.title=Brews
journal.document.alchemy_guide.brews.body=Brews are made from potion-based recipes, and are centered around inflicting harmful effects on your enemies.
journal.document.alchemy_guide.elixirs.title=Elixirs
journal.document.alchemy_guide.elixirs.body=Elixirs are made from potion-based recipes, and focus on healing or boosting your abilities.
journal.document.alchemy_guide.spells.title=Spells
journal.document.alchemy_guide.spells.body=Spells are made from scroll-based recipes, and provide a variety of effects with multiple uses.
journal.notes$landmark.well_of_health=well of health
journal.notes$landmark.well_of_awareness=well of awareness