diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index f94f33855..f72898e54 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1695,6 +1695,13 @@ items.kingscrown.upgraded=The crown glows brightly and then disintegrates as you items.kingscrown.ratgraded=Rat King's paws glow brightly as your armor transforms! items.kingscrown.desc=The crown of the last dwarven king, it glows with tremendous magical energy.\n\nWhen worn, the crown's magic will flow into the armor you're currently wearing, transforming it into a _unique epic armor with special abilities._ The new armor will keep all the properties of the original armor. +items.liquidmetal.name=liquid metal +items.liquidmetal.ac_apply=APPLY +items.liquidmetal.prompt=Select a thrown weapon +items.liquidmetal.already_fixed=That thrown weapon is already in perfect condition! +items.liquidmetal.apply=You use %d liquid metal to repair your thrown weapon. +items.liquidmetal.desc=When poured over a thrown weapon, this magical liquid will fill into the cracks and tears from use, restoring the thrown weapon to perfect condition!\n\nA tier 1 weapon requires 10 liquid metal to be fully repaired, a tier 5 weapon requires 30. Each upgrade also doubles the amount of metal needed.\n\nLiquid metal cannot be used to repair the tips on tipped darts. + items.merchantsbeacon.name=merchant's beacon items.merchantsbeacon.ac_use=USE items.merchantsbeacon.desc=This odd piece of dwarven technology allows you to communicate from great distances.\n\nAfter being activated, this beacon will let you sell items to Pixel Mart from anywhere in the dungeon.\n\nHowever, the magic within the beacon will only last for one session, so use it wisely. diff --git a/core/src/main/assets/sprites/items.png b/core/src/main/assets/sprites/items.png index c818aa6e8..97c02f68c 100644 Binary files a/core/src/main/assets/sprites/items.png and b/core/src/main/assets/sprites/items.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LiquidMetal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LiquidMetal.java new file mode 100644 index 000000000..b7197d404 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LiquidMetal.java @@ -0,0 +1,192 @@ +package com.shatteredpixel.shatteredpixeldungeon.items; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.effects.Splash; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.MagicalHolster; +import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.TippedDart; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag; +import com.watabou.noosa.audio.Sample; + +import java.util.ArrayList; + +//these aren't considered potions internally as most potion effects shouldn't apply to them +//mainly due to their high quantity +public class LiquidMetal extends Item { + + { + image = ItemSpriteSheet.LIQUID_METAL; + + stackable = true; + + defaultAction = AC_APPLY; + + bones = true; + } + + private static final String AC_APPLY = "APPLY"; + + @Override + public ArrayList actions( Hero hero ) { + ArrayList actions = super.actions( hero ); + actions.add( AC_APPLY ); + return actions; + } + + @Override + public void execute( Hero hero, String action ) { + + super.execute( hero, action ); + + if (action.equals(AC_APPLY)) { + + curUser = hero; + GameScene.selectItem( itemSelector ); + + } + } + + @Override + protected void onThrow( int cell ) { + if (Dungeon.level.map[cell] == Terrain.WELL || Dungeon.level.pit[cell]) { + + super.onThrow( cell ); + + } else { + + Dungeon.level.pressCell( cell ); + if (Dungeon.level.heroFOV[cell]) { + GLog.i( Messages.get(Potion.class, "shatter") ); + Sample.INSTANCE.play( Assets.Sounds.SHATTER ); + Splash.at( cell, 0xBFBFBF, 5 ); + } + + } + } + + @Override + public boolean isUpgradable() { + return false; + } + + @Override + public boolean isIdentified() { + return true; + } + + @Override + public int value() { + return Math.max(1, quantity/2); + } + + private final WndBag.ItemSelector itemSelector = new WndBag.ItemSelector() { + + @Override + public String textPrompt() { + return Messages.get(LiquidMetal.class, "prompt"); + } + + @Override + public Class preferredBag(){ + return MagicalHolster.class; + } + + @Override + public boolean itemSelectable(Item item) { + return item instanceof MissileWeapon && !(item instanceof TippedDart); + } + + @Override + public void onSelect( Item item ) { + if (item != null && item instanceof MissileWeapon) { + MissileWeapon m = (MissileWeapon)item; + + int maxToUse = 5*(m.tier+1); + maxToUse *= Math.pow(2, m.level()); + + float durabilityPerUse = 100 / (float)maxToUse; + + //we remove a tiny amount here to account for rounding errors + float percentDurabilityLeft = 0.999f - (m.durabilityLeft()/100f); + maxToUse = (int)Math.ceil(maxToUse*percentDurabilityLeft); + if (maxToUse == 0){ + GLog.w(Messages.get(LiquidMetal.class, "already_fixed")); + return; + } else if (maxToUse < quantity()) { + m.repair(maxToUse*durabilityPerUse); + quantity(quantity()-maxToUse); + GLog.i(Messages.get(LiquidMetal.class, "apply", maxToUse)); + + } else { + m.repair(quantity()*durabilityPerUse); + GLog.i(Messages.get(LiquidMetal.class, "apply", quantity())); + detachAll(Dungeon.hero.belongings.backpack); + } + + curUser.sprite.operate(curUser.pos); + Sample.INSTANCE.play(Assets.Sounds.DRINK); + curUser.sprite.emitter().start(Speck.factory(Speck.LIGHT), 0.1f, 10); + } + } + }; + + public static class Recipe extends com.shatteredpixel.shatteredpixeldungeon.items.Recipe { + + @Override + public boolean testIngredients(ArrayList ingredients) { + for (Item i : ingredients){ + if (!(i instanceof MissileWeapon)){ + return false; + } + } + + return !ingredients.isEmpty(); + } + + @Override + public int cost(ArrayList ingredients) { + int cost = 1; + for (Item i : ingredients){ + cost += i.quantity(); + } + return cost; + } + + @Override + public Item brew(ArrayList ingredients) { + Item result = sampleOutput(ingredients); + + for (Item i : ingredients){ + i.quantity(0); + } + + return result; + } + + @Override + public Item sampleOutput(ArrayList ingredients) { + int metalQuantity = 0; + + for (Item i : ingredients){ + MissileWeapon m = (MissileWeapon) i; + float quantity = m.quantity()-1; + quantity += 0.25f + 0.0075f*m.durabilityLeft(); + quantity *= Math.pow(2, m.level()); + metalQuantity += Math.round((5*(m.tier+1))*quantity); + } + + return new LiquidMetal().quantity(metalQuantity); + } + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java index 1d339be8e..603455a03 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java @@ -56,6 +56,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.spells.ReclaimTrap; import com.shatteredpixel.shatteredpixeldungeon.items.spells.Recycle; import com.shatteredpixel.shatteredpixeldungeon.items.spells.WildEnergy; import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon; import com.watabou.utils.Reflection; import java.util.ArrayList; @@ -163,6 +164,10 @@ public abstract class Recipe { //******* // Static members //******* + + private static Recipe[] variableRecipes = new Recipe[]{ + new LiquidMetal.Recipe() + }; private static Recipe[] oneIngredientRecipes = new Recipe[]{ new AlchemistsToolkit.upgradeKit(), @@ -209,7 +214,13 @@ public abstract class Recipe { }; public static Recipe findRecipe(ArrayList ingredients){ - + + for (Recipe recipe : variableRecipes){ + if (recipe.testIngredients(ingredients)){ + return recipe; + } + } + if (ingredients.size() == 1){ for (Recipe recipe : oneIngredientRecipes){ if (recipe.testIngredients(ingredients)){ @@ -237,7 +248,7 @@ public abstract class Recipe { public static boolean usableInRecipe(Item item){ return !item.cursed - && (!(item instanceof EquipableItem) || (item instanceof AlchemistsToolkit && item.isIdentified())) + && (!(item instanceof EquipableItem) || (item instanceof AlchemistsToolkit && item.isIdentified()) || item instanceof MissileWeapon) && !(item instanceof Wand); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/bags/PotionBandolier.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/bags/PotionBandolier.java index 7ea6c86b2..0effb0e61 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/bags/PotionBandolier.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/bags/PotionBandolier.java @@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.bags; import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.LiquidMetal; import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; @@ -33,7 +34,7 @@ public class PotionBandolier extends Bag { @Override public boolean canHold( Item item ) { - if (item instanceof Potion){ + if (item instanceof Potion || item instanceof LiquidMetal){ return super.canHold(item); } else { return false; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java index fcf172ffd..e1ca64740 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java @@ -257,6 +257,14 @@ abstract public class MissileWeapon extends Weapon { parent = null; super.onThrow(cell); } + + public float durabilityLeft(){ + return durability; + } + + public void repair( float amount ){ + durability += amount; + } protected float durabilityPerUse(){ float usages = baseUses * (float)(Math.pow(3, level())); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java index 1273262b1..9c7d5f301 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java @@ -466,10 +466,12 @@ public class ItemSpriteSheet { public static final int SCROLL_TIWAZ = SCROLLS+11; public static final int SCROLL_CATALYST = SCROLLS+13; + public static final int ARCANE_RESIN = SCROLLS+14; static { for (int i = SCROLLS; i < SCROLLS+16; i++) assignItemRect(i, 15, 14); assignItemRect(SCROLL_CATALYST, 12, 11); + assignItemRect(ARCANE_RESIN , 12, 11); } private static final int EXOTIC_SCROLLS = xy(1, 20); //16 slots @@ -522,10 +524,12 @@ public class ItemSpriteSheet { public static final int POTION_SILVER = POTIONS+10; public static final int POTION_IVORY = POTIONS+11; public static final int POTION_CATALYST = POTIONS+13; + public static final int LIQUID_METAL = POTIONS+14; static { for (int i = POTIONS; i < POTIONS+16; i++) assignItemRect(i, 12, 14); assignItemRect(POTION_CATALYST, 6, 15); + assignItemRect(LIQUID_METAL, 8, 15); } private static final int EXOTIC_POTIONS = xy(1, 23); //16 slots