diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index f72898e54..50a7424a6 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1140,6 +1140,8 @@ items.wands.wand.fizzles=Your wand fizzles; it must not have enough charge. items.wands.wand.no_magic=Your wand fizzles; you cannot use wands while magic immune. items.wands.wand.self_target=You can't target yourself! items.wands.wand.identify=You are now familiar enough with your wand to identify it. +items.wands.wand.resin_one=This wand has gained _1 level_ from arcane resin. +items.wands.wand.resin_many=This wand has gained _%d levels_ from arcane resin. items.wands.wand.cursed=This wand is cursed, making its magic chaotic and random. items.wands.wand.not_cursed=This wand is free of malevolent magic. items.wands.wand.curse_discover=This %s is cursed! @@ -1629,6 +1631,13 @@ items.ankh.bless=You bless the ankh with magical water. items.ankh.desc=This ancient symbol of immortality grants the ability to return to life after death. Upon resurrection all non-equipped items are lost. Using a full waterskin, the ankh can be blessed with extra strength. items.ankh.desc_blessed=This ancient symbol of immortality grants the ability to return to life after death. The ankh has been blessed and is now much stronger. The Ankh will sacrifice itself to save you in a moment of deadly peril. +items.arcaneresin.name=arcane resin +items.arcaneresin.ac_apply=APPLY +items.arcaneresin.level_too_high=That wand is too powerful for resin to improve. +items.arcaneresin.not_enough=You don't have enough resin for that! +items.arcaneresin.apply=You coat your wand with resin, increasing its power! +items.arcaneresin.desc=This fine powder shimmers between shades of purple and white. It can act as an amplifier to magical energies, increasing the level of wands when it is applied to them!\n\nUpgrading a wand costs 1, 2, or 3 resin depending on the wand's initial level. Resin can upgrade wands to a maximum of +3.\n\nResin upgrades are overridden by scrolls of upgrade and similar items, and do not apply when imbuing a wand into the Mage's staff. + items.brokenseal.name=broken seal items.brokenseal.ac_affix=AFFIX items.brokenseal.prompt=Select an armor diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/WaterOfTransmutation.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/WaterOfTransmutation.java index 7512c558b..2f03aeeb2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/WaterOfTransmutation.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/blobs/WaterOfTransmutation.java @@ -187,12 +187,16 @@ public class WaterOfTransmutation extends WellWater { n.level( 0 ); int level = w.level(); if (w.curseInfusionBonus) level--; + level -= n.resinBonus; n.upgrade( level ); n.levelKnown = w.levelKnown; n.cursedKnown = w.cursedKnown; n.cursed = w.cursed; n.curseInfusionBonus = w.curseInfusionBonus; + n.resinBonus = w.resinBonus; + + n.updateLevel(); return n; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/ArcaneResin.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/ArcaneResin.java new file mode 100644 index 000000000..b4cc613f4 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/ArcaneResin.java @@ -0,0 +1,154 @@ +package com.shatteredpixel.shatteredpixeldungeon.items; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.MagicalHolster; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; +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; + +public class ArcaneResin extends Item { + + { + image = ItemSpriteSheet.ARCANE_RESIN; + + 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 + public boolean isUpgradable() { + return false; + } + + @Override + public boolean isIdentified() { + return true; + } + + @Override + public int value() { + return 30*quantity(); + } + + 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 Wand && item.isIdentified(); + } + + @Override + public void onSelect( Item item ) { + if (item != null && item instanceof Wand) { + Wand w = (Wand)item; + + if (w.level() >= 3){ + GLog.w(Messages.get(ArcaneResin.class, "level_too_high")); + return; + } + + int resinToUse = w.level()+1; + + if (quantity() < resinToUse){ + GLog.w(Messages.get(ArcaneResin.class, "not_enough")); + + } else { + + if (resinToUse < quantity()){ + quantity(quantity()-resinToUse); + } else { + detachAll(Dungeon.hero.belongings.backpack); + } + + w.resinBonus++; + w.curCharges++; + w.updateLevel(); + Item.updateQuickslot(); + + curUser.sprite.operate(curUser.pos); + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + curUser.sprite.emitter().start( Speck.factory( Speck.UP ), 0.2f, 3 ); + + curUser.spendAndNext(Actor.TICK); + GLog.p(Messages.get(ArcaneResin.class, "apply")); + } + } + } + }; + + public static class Recipe extends com.shatteredpixel.shatteredpixeldungeon.items.Recipe { + + @Override + public boolean testIngredients(ArrayList ingredients) { + return ingredients.size() == 1 && ingredients.get(0) instanceof Wand && ingredients.get(0).isIdentified(); + } + + @Override + public int cost(ArrayList ingredients) { + return 5; + } + + @Override + public Item brew(ArrayList ingredients) { + Item result = sampleOutput(ingredients); + + ingredients.get(0).quantity(0); + + return result; + } + + @Override + public Item sampleOutput(ArrayList ingredients) { + Wand w = (Wand)ingredients.get(0); + int level = w.level() - w.resinBonus; + return new ArcaneResin().quantity(2*(level+1)); + } + } + +} 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 603455a03..74caffeba 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Recipe.java @@ -172,6 +172,7 @@ public abstract class Recipe { private static Recipe[] oneIngredientRecipes = new Recipe[]{ new AlchemistsToolkit.upgradeKit(), new Scroll.ScrollToStone(), + new ArcaneResin.Recipe(), new StewedMeat.oneMeat() }; @@ -248,8 +249,9 @@ public abstract class Recipe { public static boolean usableInRecipe(Item item){ return !item.cursed - && (!(item instanceof EquipableItem) || (item instanceof AlchemistsToolkit && item.isIdentified()) || item instanceof MissileWeapon) - && !(item instanceof Wand); + && (!(item instanceof EquipableItem) + || (item instanceof AlchemistsToolkit && item.isIdentified()) + || item instanceof MissileWeapon); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfTransmutation.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfTransmutation.java index 46982612f..7d801bdde 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfTransmutation.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfTransmutation.java @@ -221,12 +221,16 @@ public class ScrollOfTransmutation extends InventoryScroll { n.level( 0 ); int level = w.level(); if (w.curseInfusionBonus) level--; + level -= n.resinBonus; n.upgrade( level ); n.levelKnown = w.levelKnown; n.cursedKnown = w.cursedKnown; n.cursed = w.cursed; n.curseInfusionBonus = w.curseInfusionBonus; + n.resinBonus = w.resinBonus; + + n.updateLevel(); return n; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java index d91817581..7a49adcce 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java @@ -50,6 +50,8 @@ import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.noosa.audio.Sample; @@ -75,7 +77,8 @@ public abstract class Wand extends Item { private boolean curChargeKnown = false; public boolean curseInfusionBonus = false; - + public int resinBonus = 0; + private static final int USES_TO_ID = 10; private float usesLeftToID = USES_TO_ID; private float availableUsesToID = USES_TO_ID/2f; @@ -236,6 +239,12 @@ public abstract class Wand extends Item { desc += "\n\n" + statsDesc(); + if (resinBonus == 1){ + desc += "\n\n" + Messages.get(Wand.class, "resin_one"); + } else if (resinBonus > 1){ + desc += "\n\n" + Messages.get(Wand.class, "resin_many", resinBonus); + } + if (cursed && cursedKnown) { desc += "\n\n" + Messages.get(Wand.class, "cursed"); } else if (!isIdentified() && cursedKnown){ @@ -273,7 +282,7 @@ public abstract class Wand extends Item { curseInfusionBonus = false; updateLevel(); } - return super.level() + (curseInfusionBonus ? 1 : 0); + return super.level() + resinBonus + (curseInfusionBonus ? 1 : 0); } @Override @@ -285,6 +294,10 @@ public abstract class Wand extends Item { cursed = false; } + if (resinBonus > 0){ + resinBonus--; + } + updateLevel(); curCharges = Math.min( curCharges + 1, maxCharges ); updateQuickslot(); @@ -425,7 +438,14 @@ public abstract class Wand extends Item { return this; } - + + @Override + public ItemSprite.Glowing glowing() { + if (resinBonus == 0) return null; + + return new ItemSprite.Glowing(0xFFFFFF, 1f/(float)resinBonus); + } + @Override public int value() { int price = 75; @@ -445,13 +465,14 @@ public abstract class Wand extends Item { return price; } - private static final String USES_LEFT_TO_ID = "uses_left_to_id"; - private static final String AVAILABLE_USES = "available_uses"; + private static final String USES_LEFT_TO_ID = "uses_left_to_id"; + private static final String AVAILABLE_USES = "available_uses"; private static final String CUR_CHARGES = "curCharges"; private static final String CUR_CHARGE_KNOWN = "curChargeKnown"; private static final String PARTIALCHARGE = "partialCharge"; - private static final String CURSE_INFUSION_BONUS = "curse_infusion_bonus"; - + private static final String CURSE_INFUSION_BONUS= "curse_infusion_bonus"; + private static final String RESIN_BONUS = "resin_bonus"; + @Override public void storeInBundle( Bundle bundle ) { super.storeInBundle( bundle ); @@ -460,7 +481,8 @@ public abstract class Wand extends Item { bundle.put( CUR_CHARGES, curCharges ); bundle.put( CUR_CHARGE_KNOWN, curChargeKnown ); bundle.put( PARTIALCHARGE , partialCharge ); - bundle.put(CURSE_INFUSION_BONUS, curseInfusionBonus ); + bundle.put( CURSE_INFUSION_BONUS, curseInfusionBonus ); + bundle.put( RESIN_BONUS, resinBonus ); } @Override @@ -473,6 +495,7 @@ public abstract class Wand extends Item { curChargeKnown = bundle.getBoolean( CUR_CHARGE_KNOWN ); partialCharge = bundle.getFloat( PARTIALCHARGE ); curseInfusionBonus = bundle.getBoolean(CURSE_INFUSION_BONUS); + resinBonus = bundle.getInt(RESIN_BONUS); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MagesStaff.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MagesStaff.java index 48d0829a4..5b8f07f4e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MagesStaff.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MagesStaff.java @@ -224,6 +224,9 @@ public class MagesStaff extends MeleeWeapon { this.wand = null; + wand.resinBonus = 0; + wand.updateLevel(); + //syncs the level of the two items. int targetLevel = Math.max(this.level() - (curseInfusionBonus ? 1 : 0), wand.level()); @@ -401,9 +404,11 @@ public class MagesStaff extends MeleeWeapon { applyWand((Wand)item); } else { int newLevel; - if (item.level() >= level()){ - if (level() > 0) newLevel = item.level() + 1; - else newLevel = item.level(); + int itemLevel = item.level(); + itemLevel -= ((Wand)item).resinBonus; + if (itemLevel >= level()){ + if (level() > 0) newLevel = itemLevel + 1; + else newLevel = itemLevel; } else { newLevel = level(); }