diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 81ecbbb29..6418b4be5 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -977,12 +977,6 @@ actors.mobs.npcs.blacksmith.exit_warn_gnoll=That gnoll geomancer's still down th actors.mobs.npcs.blacksmith.exit_yes=I'm Done actors.mobs.npcs.blacksmith.exit_no=Not Yet actors.mobs.npcs.blacksmith.get_lost=I'm busy. Get lost! -actors.mobs.npcs.blacksmith.same_item=Select 2 different items, not the same item twice! -actors.mobs.npcs.blacksmith.diff_type=Select 2 items of the same type! -actors.mobs.npcs.blacksmith.un_ided=I need to know what I'm working with, identify them first! -actors.mobs.npcs.blacksmith.cursed=I don't work with cursed items! -actors.mobs.npcs.blacksmith.degraded=It's junk, the quality is too poor! -actors.mobs.npcs.blacksmith.cant_reforge=I can't reforge these items! actors.mobs.npcs.blacksmith.entrance_blocked=The way down is blocked. actors.mobs.npcs.blacksmith.cant_enter_old=That area is not accessible on this run. Play a new game to try the new quest! actors.mobs.npcs.blacksmith.def_verb=blocked diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 84a2c43a0..c961ccb3d 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -77,6 +77,7 @@ items.armor.armor.ac_detach=DETACH items.armor.armor.detach_seal=You detach the seal from your armor. items.armor.armor.equip_cursed=The armor constricts around you painfully. items.armor.armor.identify=You are now familiar enough with your armor to identify it. +items.armor.armor.hardening_gone=The hardening on this armor has worn off! items.armor.armor.incompatible=Interaction of different types of magic has erased the glyph on this armor! items.armor.armor.curr_absorb=This _tier-%1$d_ armor blocks _%2$d-%3$d damage_ and requires _%4$d strength_ to use properly. items.armor.armor.avg_absorb=Typically this _tier-%1$d_ armor blocks _%2$d-%3$d damage_ and requires _%4$d strength_ to use properly. @@ -86,6 +87,8 @@ items.armor.armor.excess_str=Because of your excess strength, you are _more evas items.armor.armor.evasion=It is augmented to enhance _evasion._ items.armor.armor.defense=It is augmented to enhance _defense._ items.armor.armor.inscribed=it is inscribed with a _%s._ +items.armor.armor.glyph_hardened=It has been _hardened._ +items.armor.armor.hardened_no_glyph=This armor has been _hardened,_ but is not currently inscribed with a glyph. items.armor.armor.cursed_worn=Because this armor is cursed, you are powerless to remove it. items.armor.armor.cursed=You can feel a malevolent magic lurking within this armor. items.armor.armor.weak_cursed=Despite the curse, you are able to unequip this armor. @@ -1877,6 +1880,7 @@ items.weapon.spiritbow.desc=A bow made out of ancient magical wood. The bow's st items.weapon.weapon.identify=You are now familiar enough with your weapon to identify it. items.weapon.weapon.too_heavy=Because of your inadequate strength this weapon will hinder your attack speed, accuracy, and ability to surprise attack. items.weapon.weapon.excess_str=Because of your excess strength, you will deal up to _%d bonus damage_ with this weapon. +items.weapon.weapon.hardening_gone=The hardening on this weapon has worn off! items.weapon.weapon.incompatible=Interaction of different types of magic has negated the enchantment on this weapon! items.weapon.weapon.cursed_worn=Because this weapon is cursed, you are powerless to remove it. items.weapon.weapon.cursed=You can feel a malevolent magic lurking within this weapon. @@ -1885,6 +1889,8 @@ items.weapon.weapon.not_cursed=This weapon is free of malevolent magic. items.weapon.weapon.faster=It is augmented to enhance _speed._ items.weapon.weapon.stronger=It is augmented to enhance _damage._ items.weapon.weapon.enchanted=it has a _%s._ +items.weapon.weapon.enchant_hardened=It has been _hardened._ +items.weapon.weapon.hardened_no_enchant=This weapon has been _hardened,_ but is not currently enchanted. items.weapon.weapon$enchantment.enchant=enchantment diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index 693055235..5135d8169 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -1,6 +1,16 @@ -windows.wndblacksmithold.prompt=Ok, a deal is a deal, here's what I can do for you: I can reforge 2 items and turn them into one of a better quality. -windows.wndblacksmithold.select=Reforge an item -windows.wndblacksmithold.reforge=Reforge them +windows.wndblacksmith.prompt=Okay, a deal's a deal. Here's what I can do for you.\n\n_Current Favor: %d_ +windows.wndblacksmith.pickaxe=_Pickaxe (%d favor):_ I guess I can give you the pickaxe back if you want. I've got plenty more. +windows.wndblacksmith.reforge=_Reforge (%d favor):_ I can reforge two of the same type of identified item into one of a higher quality. +windows.wndblacksmith.harden=_Harden (%d favor):_ I can harden an identified weapon or armor, so it's easier to keep an enchantment or glyph. +windows.wndblacksmith.upgrade=_Upgrade (%d favor):_ If you've got an identified item below +3 I can upgrade it for you. +windows.wndblacksmith.smith=_Smith (%d favor):_ I can try forging a weapon or armor for you from scratch. It'll be higher tier and probably upgraded, and you'll get some choice over what you get. +windows.wndblacksmith.cashout=_Cash Out (%d favor):_ I can just give you some regular gold I've got lyin' around. +windows.wndblacksmith$wndreforge.message=Okay, I can reforge two identified items of the same type and turn them into one of a better quality. +windows.wndblacksmith$wndreforge.prompt=Reforge an item +windows.wndblacksmith$wndreforge.reforge=Reforge them +windows.wndblacksmith$hardenselector.prompt=Harden an item +windows.wndblacksmith$upgradeselector.prompt=Upgrade an item +windows.wndblacksmith$wndsmith.prompt=Okay, here's what I can make. I've already got the forge fired up so choose quickly. windows.wndchallenges.title=Challenges diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Blacksmith.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Blacksmith.java index 879f7c6da..c3566808e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Blacksmith.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Blacksmith.java @@ -21,21 +21,14 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs; -import com.shatteredpixel.shatteredpixeldungeon.Assets; -import com.shatteredpixel.shatteredpixeldungeon.Badges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AscensionChallenge; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; -import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; -import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem; import com.shatteredpixel.shatteredpixeldungeon.items.Item; -import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; import com.shatteredpixel.shatteredpixeldungeon.items.quest.DarkGold; import com.shatteredpixel.shatteredpixeldungeon.items.quest.Pickaxe; -import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; -import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.quest.BlacksmithRoom; @@ -44,10 +37,8 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.BlacksmithSprite; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.windows.WndBlacksmith; -import com.shatteredpixel.shatteredpixeldungeon.windows.WndBlacksmithOld; import com.shatteredpixel.shatteredpixeldungeon.windows.WndQuest; import com.watabou.noosa.Game; -import com.watabou.noosa.audio.Sample; import com.watabou.utils.Bundle; import com.watabou.utils.Callback; import com.watabou.utils.Random; @@ -203,7 +194,7 @@ public class Blacksmith extends NPC { Game.runOnRenderThread(new Callback() { @Override public void call() { - GameScene.show( new WndBlacksmithOld( Blacksmith.this, Dungeon.hero ) ); + GameScene.show( new WndBlacksmith.WndReforge( Blacksmith.this, Dungeon.hero ) ); } }); @@ -233,85 +224,7 @@ public class Blacksmith extends NPC { } }); } - - public static String verify( Item item1, Item item2 ) { - - if (item1 == item2 && (item1.quantity() == 1 && item2.quantity() == 1)) { - return Messages.get(Blacksmith.class, "same_item"); - } - if (item1.getClass() != item2.getClass()) { - return Messages.get(Blacksmith.class, "diff_type"); - } - - if (!item1.isIdentified() || !item2.isIdentified()) { - return Messages.get(Blacksmith.class, "un_ided"); - } - - if (item1.cursed || item2.cursed || - (item1 instanceof Armor && ((Armor) item1).hasCurseGlyph()) || - (item2 instanceof Armor && ((Armor) item2).hasCurseGlyph()) || - (item1 instanceof Weapon && ((Weapon) item1).hasCurseEnchant()) || - (item2 instanceof Weapon && ((Weapon) item2).hasCurseEnchant())) { - return Messages.get(Blacksmith.class, "cursed"); - } - - if (item1.level() < 0 || item2.level() < 0) { - return Messages.get(Blacksmith.class, "degraded"); - } - - if (!item1.isUpgradable() || !item2.isUpgradable()) { - return Messages.get(Blacksmith.class, "cant_reforge"); - } - - return null; - } - - public static void upgrade( Item item1, Item item2 ) { - - Item first, second; - if (item2.trueLevel() > item1.trueLevel()) { - first = item2; - second = item1; - } else { - first = item1; - second = item2; - } - - Sample.INSTANCE.play( Assets.Sounds.EVOKE ); - ScrollOfUpgrade.upgrade( Dungeon.hero ); - Item.evoke( Dungeon.hero ); - - if (second.isEquipped( Dungeon.hero )) { - ((EquipableItem)second).doUnequip( Dungeon.hero, false ); - } - second.detach( Dungeon.hero.belongings.backpack ); - - if (second instanceof Armor){ - BrokenSeal seal = ((Armor) second).checkSeal(); - if (seal != null){ - Dungeon.level.drop( seal, Dungeon.hero.pos ); - } - } - - //preserves enchant/glyphs if present - if (first instanceof Weapon && ((Weapon) first).hasGoodEnchant()){ - ((Weapon) first).upgrade(true); - } else if (first instanceof Armor && ((Armor) first).hasGoodGlyph()){ - ((Armor) first).upgrade(true); - } else { - first.upgrade(); - } - Dungeon.hero.spendAndNext( 2f ); - Badges.validateItemLevelAquired( first ); - Item.updateQuickslot(); - - Quest.reforges++; - if (Quest.type != 0) { - Quest.favor -= 500; - } - } - @Override public int defenseSkill( Char enemy ) { return INFINITE_EVASION; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java index 27e292e2d..05e71b82e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java @@ -104,6 +104,7 @@ public class Armor extends EquipableItem { public Augment augment = Augment.NONE; public Glyph glyph; + public boolean glyphHardened = false; public boolean curseInfusionBonus = false; public boolean masteryPotionBonus = false; @@ -122,6 +123,7 @@ public class Armor extends EquipableItem { private static final String USES_LEFT_TO_ID = "uses_left_to_id"; private static final String AVAILABLE_USES = "available_uses"; private static final String GLYPH = "glyph"; + private static final String GLYPH_HARDENED = "glyph_hardened"; private static final String CURSE_INFUSION_BONUS = "curse_infusion_bonus"; private static final String MASTERY_POTION_BONUS = "mastery_potion_bonus"; private static final String SEAL = "seal"; @@ -133,6 +135,7 @@ public class Armor extends EquipableItem { bundle.put( USES_LEFT_TO_ID, usesLeftToID ); bundle.put( AVAILABLE_USES, availableUsesToID ); bundle.put( GLYPH, glyph ); + bundle.put( GLYPH_HARDENED, glyphHardened ); bundle.put( CURSE_INFUSION_BONUS, curseInfusionBonus ); bundle.put( MASTERY_POTION_BONUS, masteryPotionBonus ); bundle.put( SEAL, seal); @@ -145,6 +148,7 @@ public class Armor extends EquipableItem { usesLeftToID = bundle.getInt( USES_LEFT_TO_ID ); availableUsesToID = bundle.getInt( AVAILABLE_USES ); inscribe((Glyph) bundle.get(GLYPH)); + glyphHardened = bundle.getBoolean(GLYPH_HARDENED); curseInfusionBonus = bundle.getBoolean( CURSE_INFUSION_BONUS ); masteryPotionBonus = bundle.getBoolean( MASTERY_POTION_BONUS ); seal = (BrokenSeal)bundle.get(SEAL); @@ -393,11 +397,21 @@ public class Armor extends EquipableItem { if (glyph == null){ inscribe( Glyph.random() ); } - } else { - if (hasCurseGlyph()){ + } else if (glyph != null) { + //chance to lose harden buff is 10/20/40/80/100% when upgrading from +6/7/8/9/10 + if (glyphHardened) { + if (level() >= 6 && Random.Float(10) < Math.pow(2, level()-6)){ + glyphHardened = false; + } + + //chance to remove curse is a static 33% + } else if (hasCurseGlyph()){ if (Random.Int(3) == 0) inscribe(null); + + //otherwise chance to lose glyph is 10/20/40/80/100% when upgrading from +4/5/6/7/8 } else { + //the chance from +4/5, and then +6 can be set to 0% with metamorphed runic transference int lossChanceStart = 4; if (Dungeon.hero != null && Dungeon.hero.heroClass != HeroClass.WARRIOR && Dungeon.hero.hasTalent(Talent.RUNIC_TRANSFERENCE)){ lossChanceStart += 1+Dungeon.hero.pointsInTalent(Talent.RUNIC_TRANSFERENCE); @@ -491,7 +505,10 @@ public class Armor extends EquipableItem { if (glyph != null && (cursedKnown || !glyph.curse())) { info += "\n\n" + Messages.capitalize(Messages.get(Armor.class, "inscribed", glyph.name())); + if (glyphHardened) info += " " + Messages.get(Armor.class, "glyph_hardened"); info += " " + glyph.desc(); + } else if (glyphHardened){ + info += "\n\n" + Messages.get(Armor.class, "hardened_no_glyph"); } if (cursed && isEquipped( Dungeon.hero )) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfUpgrade.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfUpgrade.java index 713500855..d937f5740 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfUpgrade.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/ScrollOfUpgrade.java @@ -65,6 +65,7 @@ public class ScrollOfUpgrade extends InventoryScroll { if (item instanceof Weapon){ Weapon w = (Weapon) item; boolean wasCursed = w.cursed; + boolean wasHardened = w.enchantHardened; boolean hadCursedEnchant = w.hasCurseEnchant(); boolean hadGoodEnchant = w.hasGoodEnchant(); @@ -75,13 +76,16 @@ public class ScrollOfUpgrade extends InventoryScroll { } else if (w.cursedKnown && wasCursed && !w.cursed){ weakenCurse( Dungeon.hero ); } - if (hadGoodEnchant && !w.hasGoodEnchant()){ + if (wasHardened && !w.enchantHardened){ + GLog.w( Messages.get(Weapon.class, "hardening_gone") ); + } else if (hadGoodEnchant && !w.hasGoodEnchant()){ GLog.w( Messages.get(Weapon.class, "incompatible") ); } } else if (item instanceof Armor){ Armor a = (Armor) item; boolean wasCursed = a.cursed; + boolean wasHardened = a.glyphHardened; boolean hadCursedGlyph = a.hasCurseGlyph(); boolean hadGoodGlyph = a.hasGoodGlyph(); @@ -92,7 +96,9 @@ public class ScrollOfUpgrade extends InventoryScroll { } else if (a.cursedKnown && wasCursed && !a.cursed){ weakenCurse( Dungeon.hero ); } - if (hadGoodGlyph && !a.hasGoodGlyph()){ + if (wasHardened && !a.glyphHardened){ + GLog.w( Messages.get(Armor.class, "hardening_gone") ); + } else if (hadGoodGlyph && !a.hasGoodGlyph()){ GLog.w( Messages.get(Armor.class, "incompatible") ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java index a60dc42aa..b9a9e0c69 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java @@ -103,6 +103,7 @@ abstract public class Weapon extends KindOfWeapon { private float availableUsesToID = USES_TO_ID/2f; public Enchantment enchantment; + public boolean enchantHardened = false; public boolean curseInfusionBonus = false; public boolean masteryPotionBonus = false; @@ -138,6 +139,7 @@ abstract public class Weapon extends KindOfWeapon { private static final String USES_LEFT_TO_ID = "uses_left_to_id"; private static final String AVAILABLE_USES = "available_uses"; private static final String ENCHANTMENT = "enchantment"; + private static final String ENCHANT_HARDENED = "enchant_hardened"; private static final String CURSE_INFUSION_BONUS = "curse_infusion_bonus"; private static final String MASTERY_POTION_BONUS = "mastery_potion_bonus"; private static final String AUGMENT = "augment"; @@ -148,6 +150,7 @@ abstract public class Weapon extends KindOfWeapon { bundle.put( USES_LEFT_TO_ID, usesLeftToID ); bundle.put( AVAILABLE_USES, availableUsesToID ); bundle.put( ENCHANTMENT, enchantment ); + bundle.put( ENCHANT_HARDENED, enchantHardened ); bundle.put( CURSE_INFUSION_BONUS, curseInfusionBonus ); bundle.put( MASTERY_POTION_BONUS, masteryPotionBonus ); bundle.put( AUGMENT, augment ); @@ -159,6 +162,7 @@ abstract public class Weapon extends KindOfWeapon { usesLeftToID = bundle.getFloat( USES_LEFT_TO_ID ); availableUsesToID = bundle.getFloat( AVAILABLE_USES ); enchantment = (Enchantment)bundle.get( ENCHANTMENT ); + enchantHardened = bundle.getBoolean( ENCHANT_HARDENED ); curseInfusionBonus = bundle.getBoolean( CURSE_INFUSION_BONUS ); masteryPotionBonus = bundle.getBoolean( MASTERY_POTION_BONUS ); @@ -268,9 +272,18 @@ abstract public class Weapon extends KindOfWeapon { if (enchantment == null){ enchant(Enchantment.random()); } - } else { - if (hasCurseEnchant()){ + } else if (enchantment != null) { + //chance to lose harden buff is 10/20/40/80/100% when upgrading from +6/7/8/9/10 + if (enchantHardened){ + if (level() >= 6 && Random.Float(10) < Math.pow(2, level()-6)){ + enchantHardened = false; + } + + //chance to remove curse is a static 33% + } else if (hasCurseEnchant()) { if (Random.Int(3) == 0) enchant(null); + + //otherwise chance to lose enchant is 10/20/40/80/100% when upgrading from +4/5/6/7/8 } else if (level() >= 4 && Random.Float(10) < Math.pow(2, level()-4)){ enchant(null); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java index ba9c1cd4b..81ea7cc41 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java @@ -387,7 +387,10 @@ public class MeleeWeapon extends Weapon { if (enchantment != null && (cursedKnown || !enchantment.curse())){ info += "\n\n" + Messages.capitalize(Messages.get(Weapon.class, "enchanted", enchantment.name())); + if (enchantHardened) info += " " + Messages.get(Weapon.class, "enchant_hardened"); info += " " + enchantment.desc(); + } else if (enchantHardened){ + info += "\n\n" + Messages.get(Weapon.class, "hardened_no_enchant"); } if (cursed && isEquipped( Dungeon.hero )) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmith.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmith.java index 93816859d..30c02c6b8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmith.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmith.java @@ -21,15 +21,33 @@ package com.shatteredpixel.shatteredpixeldungeon.windows; +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Badges; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.Statistics; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith; +import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; +import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem; +import com.shatteredpixel.shatteredpixeldungeon.items.Generator; +import com.shatteredpixel.shatteredpixeldungeon.items.Gold; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; +import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.ui.ItemButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Random; import java.util.ArrayList; @@ -40,8 +58,7 @@ public class WndBlacksmith extends Window { private static final int GAP = 2; - //A LOT still to do here! - public WndBlacksmith(Blacksmith troll, Hero hero ) { + public WndBlacksmith( Blacksmith troll, Hero hero ) { super(); int width = PixelScene.landscape() ? WIDTH_L : WIDTH_P; @@ -52,30 +69,83 @@ public class WndBlacksmith extends Window { titlebar.setRect( 0, 0, width, 0 ); add( titlebar ); - RenderedTextBlock message = PixelScene.renderTextBlock( Messages.get(this, "prompt"), 6 ); + RenderedTextBlock message = PixelScene.renderTextBlock( Messages.get(this, "prompt", Blacksmith.Quest.favor), 6 ); message.maxWidth( width ); message.setPos(0, titlebar.bottom() + GAP); add( message ); - ArrayList buttons = new ArrayList<>(); - //TODO - RedButton pickaxe = new RedButton("_Pickaxe (250 favor):_ \"I guess I can give you the pickaxe back if you really want it. I've got plenty more.\"", 6){ + int pickaxeCost = Statistics.questScores[2] >= 2500 ? 0 : 250; + RedButton pickaxe = new RedButton(Messages.get(this, "pickaxe", pickaxeCost), 6){ @Override protected void onClick() { - Blacksmith.Quest.pickaxe.collect(Dungeon.hero.belongings.backpack); - Blacksmith.Quest.favor -= 250; + if (Blacksmith.Quest.pickaxe.doPickUp( Dungeon.hero )) { + GLog.i( Messages.capitalize(Messages.get(Dungeon.hero, "you_now_have", Blacksmith.Quest.pickaxe.name()) )); + } else { + Dungeon.level.drop( Blacksmith.Quest.pickaxe, Dungeon.hero.pos ).sprite.drop(); + } + Blacksmith.Quest.favor -= pickaxeCost; Blacksmith.Quest.pickaxe = null; WndBlacksmith.this.hide(); - if (Blacksmith.Quest.favor > 0) { - GameScene.show(new WndBlacksmith(troll, hero)); - } } }; - pickaxe.enable(Blacksmith.Quest.pickaxe != null && Blacksmith.Quest.favor >= 250); + pickaxe.enable(Blacksmith.Quest.pickaxe != null && Blacksmith.Quest.favor >= pickaxeCost); buttons.add(pickaxe); + int reforgecost = 500 * (int)Math.pow(2, Blacksmith.Quest.reforges); + RedButton reforge = new RedButton(Messages.get(this, "reforge", reforgecost), 6){ + @Override + protected void onClick() { + WndBlacksmith.this.hide(); + GameScene.show(new WndReforge(troll, hero)); + } + }; + reforge.enable(Blacksmith.Quest.favor >= reforgecost); + buttons.add(reforge); + + int hardenCost = 500 * (int)Math.pow(2, Blacksmith.Quest.hardens); + RedButton harden = new RedButton(Messages.get(this, "harden", hardenCost), 6){ + @Override + protected void onClick() { + GameScene.selectItem(new HardenSelector()); + } + }; + harden.enable(Blacksmith.Quest.favor >= hardenCost); + buttons.add(harden); + + int upgradeCost = 1000 * (int)Math.pow(2, Blacksmith.Quest.upgrades); + RedButton upgrade = new RedButton(Messages.get(this, "upgrade", upgradeCost), 6){ + @Override + protected void onClick() { + GameScene.selectItem(new UpgradeSelector()); + } + }; + upgrade.enable(Blacksmith.Quest.favor >= upgradeCost); + buttons.add(upgrade); + + RedButton smith = new RedButton(Messages.get(this, "smith", 2000), 6){ + @Override + protected void onClick() { + Blacksmith.Quest.favor -= 2000; + Blacksmith.Quest.smiths++; + WndBlacksmith.this.hide(); + GameScene.show(new WndSmith(troll, hero)); + } + }; + smith.enable(Blacksmith.Quest.favor >= 2000); + buttons.add(smith); + + RedButton cashOut = new RedButton(Messages.get(this, "cashout", Blacksmith.Quest.favor), 6){ + @Override + protected void onClick() { + new Gold(Blacksmith.Quest.favor).doPickUp(Dungeon.hero, Dungeon.hero.pos); + Blacksmith.Quest.favor = 0; + WndBlacksmith.this.hide(); + } + }; + cashOut.enable(true); + buttons.add(cashOut); float pos = message.bottom() + 3*GAP; for (RedButton b : buttons){ @@ -92,4 +162,345 @@ public class WndBlacksmith extends Window { } + //public so that it can be directly called for pre-v2.2.0 quest completions + public static class WndReforge extends Window { + + private static final int WIDTH = 120; + + private static final int BTN_SIZE = 32; + private static final float GAP = 2; + private static final float BTN_GAP = 5; + + private ItemButton btnPressed; + + private ItemButton btnItem1; + private ItemButton btnItem2; + private RedButton btnReforge; + + public WndReforge( Blacksmith troll, Hero hero ) { + super(); + + IconTitle titlebar = new IconTitle(); + titlebar.icon( troll.sprite() ); + titlebar.label( Messages.titleCase( troll.name() ) ); + titlebar.setRect( 0, 0, WIDTH, 0 ); + add( titlebar ); + + RenderedTextBlock message = PixelScene.renderTextBlock( Messages.get(this, "message"), 6 ); + message.maxWidth( WIDTH); + message.setPos(0, titlebar.bottom() + GAP); + add( message ); + + btnItem1 = new ItemButton() { + @Override + protected void onClick() { + btnPressed = btnItem1; + GameScene.selectItem( itemSelector ); + } + }; + btnItem1.setRect( (WIDTH - BTN_GAP) / 2 - BTN_SIZE, message.top() + message.height() + BTN_GAP, BTN_SIZE, BTN_SIZE ); + add( btnItem1 ); + + btnItem2 = new ItemButton() { + @Override + protected void onClick() { + btnPressed = btnItem2; + GameScene.selectItem( itemSelector ); + } + }; + btnItem2.setRect( btnItem1.right() + BTN_GAP, btnItem1.top(), BTN_SIZE, BTN_SIZE ); + add( btnItem2 ); + + btnReforge = new RedButton( Messages.get(this, "reforge") ) { + @Override + protected void onClick() { + + Item first, second; + if (btnItem1.item().trueLevel() > btnItem2.item().trueLevel()) { + first = btnItem1.item(); + second = btnItem2.item(); + } else { + first = btnItem2.item(); + second = btnItem1.item(); + } + + Sample.INSTANCE.play( Assets.Sounds.EVOKE ); + ScrollOfUpgrade.upgrade( Dungeon.hero ); + Item.evoke( Dungeon.hero ); + + if (second.isEquipped( Dungeon.hero )) { + ((EquipableItem)second).doUnequip( Dungeon.hero, false ); + } + second.detach( Dungeon.hero.belongings.backpack ); + + if (second instanceof Armor){ + BrokenSeal seal = ((Armor) second).checkSeal(); + if (seal != null){ + Dungeon.level.drop( seal, Dungeon.hero.pos ); + } + } + + //preserves enchant/glyphs if present + if (first instanceof Weapon && ((Weapon) first).hasGoodEnchant()){ + ((Weapon) first).upgrade(true); + } else if (first instanceof Armor && ((Armor) first).hasGoodGlyph()){ + ((Armor) first).upgrade(true); + } else { + first.upgrade(); + } + Badges.validateItemLevelAquired( first ); + Item.updateQuickslot(); + + Blacksmith.Quest.favor -= 500 * (int)Math.pow(2, Blacksmith.Quest.reforges); + Blacksmith.Quest.reforges++; + + hide(); + } + }; + btnReforge.enable( false ); + btnReforge.setRect( 0, btnItem1.bottom() + BTN_GAP, WIDTH, 20 ); + add( btnReforge ); + + + resize( WIDTH, (int)btnReforge.bottom() ); + } + + protected WndBag.ItemSelector itemSelector = new WndBag.ItemSelector() { + + @Override + public String textPrompt() { + return Messages.get(WndReforge.class, "prompt"); + } + + @Override + public Class preferredBag(){ + return Belongings.Backpack.class; + } + + @Override + public boolean itemSelectable(Item item) { + return item.isIdentified() && item.isUpgradable(); + } + + @Override + public void onSelect( Item item ) { + if (item != null && btnPressed.parent != null) { + btnPressed.item(item); + + Item item1 = btnItem1.item(); + Item item2 = btnItem2.item(); + + //need 2 items + if (item1 == null || item2 == null) { + btnReforge.enable(false); + + //both of the same type + } else if (item1.getClass() != item2.getClass()) { + btnReforge.enable(false); + + //and not the literal same item (unless quantity is >1) + } else if (item1 == item2 && item1.quantity() == 1) { + btnReforge.enable(false); + + } else { + btnReforge.enable(true); + } + } + } + }; + + } + + private class HardenSelector extends WndBag.ItemSelector { + + @Override + public String textPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + public Class preferredBag(){ + return Belongings.Backpack.class; + } + + @Override + public boolean itemSelectable(Item item) { + return item.isUpgradable() + && item.isIdentified() + && ((item instanceof MeleeWeapon && !((Weapon) item).enchantHardened) + || (item instanceof Armor && !((Armor) item).glyphHardened)); + } + + @Override + public void onSelect(Item item) { + if (item != null) { + if (item instanceof Weapon){ + ((Weapon) item).enchantHardened = true; + } else if (item instanceof Armor){ + ((Armor) item).glyphHardened = true; + } + + int hardenCost = Blacksmith.Quest.hardens == 0 ? 500 : 1000; + Blacksmith.Quest.favor -= hardenCost; + Blacksmith.Quest.hardens++; + + WndBlacksmith.this.hide(); + + Sample.INSTANCE.play(Assets.Sounds.EVOKE); + Item.evoke( Dungeon.hero ); + } + } + } + + private class UpgradeSelector extends WndBag.ItemSelector { + + @Override + public String textPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + public Class preferredBag(){ + return Belongings.Backpack.class; + } + + @Override + public boolean itemSelectable(Item item) { + return item.isUpgradable() + && item.isIdentified() + && item.level() < 3; + } + + @Override + public void onSelect(Item item) { + if (item != null) { + item.upgrade(); + int upgradeCost = Blacksmith.Quest.upgrades == 0 ? 1000 : 1500; + Blacksmith.Quest.favor -= upgradeCost; + Blacksmith.Quest.upgrades++; + + WndBlacksmith.this.hide(); + + Sample.INSTANCE.play(Assets.Sounds.EVOKE); + ScrollOfUpgrade.upgrade( Dungeon.hero ); + Item.evoke( Dungeon.hero ); + } + } + } + + public static class WndSmith extends Window { + + private static final int WIDTH = 120; + private static final int BTN_SIZE = 32; + private static final int BTN_GAP = 5; + private static final int GAP = 2; + + Item[] rewards = new Item[3]; + + int rewardLevel; + + public WndSmith( Blacksmith troll, Hero hero ){ + super(); + + IconTitle titlebar = new IconTitle(); + titlebar.icon(troll.sprite()); + titlebar.label(Messages.titleCase(troll.name())); + + RenderedTextBlock message = PixelScene.renderTextBlock( Messages.get(this, "prompt"), 6 ); + + titlebar.setRect( 0, 0, WIDTH, 0 ); + add( titlebar ); + + message.maxWidth(WIDTH); + message.setPos(0, titlebar.bottom() + GAP); + add( message ); + + rewards[0] = Generator.randomWeapon(3, true); + do { + rewards[1] = Generator.randomWeapon(3, true); + } while (rewards[0].getClass() == rewards[1].getClass()); + rewards[2] = Generator.randomArmor(3); + + //15%:+0, 55%:+1, 20%:+2, 5%:+3 + float itemLevelRoll = Random.Float(); + if (itemLevelRoll < 0.2f){ + rewardLevel = 0; + } else if (itemLevelRoll < 0.75f){ + rewardLevel = 1; + } else if (itemLevelRoll < 0.95f){ + rewardLevel = 2; + } else { + rewardLevel = 3; + } + + int count = 0; + for (Item i : rewards){ + count++; + i.level(rewardLevel); + if (i instanceof Weapon) { + ((Weapon) i).enchant(null); + } else if (i instanceof Armor){ + ((Armor) i).inscribe(null); + } + i.cursed = false; + + ItemButton btnReward = new ItemButton(){ + @Override + protected void onClick() { + GameScene.show(new RewardWindow(troll, hero, item())); + } + }; + btnReward.item( i ); + btnReward.setRect( count*(WIDTH - BTN_GAP) / 3 - BTN_SIZE, message.top() + message.height() + BTN_GAP, BTN_SIZE, BTN_SIZE ); + add( btnReward ); + + } + + resize(WIDTH, (int)message.bottom() + 2*BTN_GAP + BTN_SIZE); + + } + + @Override + public void onBackPressed() { + //do nothing + } + + private class RewardWindow extends WndInfoItem { + + public RewardWindow( Blacksmith troll, Hero hero, Item item ) { + super(item); + + RedButton btnConfirm = new RedButton(Messages.get(WndSadGhost.class, "confirm")){ + @Override + protected void onClick() { + RewardWindow.this.hide(); + item.identify(false); + Sample.INSTANCE.play(Assets.Sounds.EVOKE); + Item.evoke( Dungeon.hero ); + if (item.doPickUp( Dungeon.hero )) { + GLog.i( Messages.capitalize(Messages.get(Dungeon.hero, "you_now_have", item.name())) ); + } else { + Dungeon.level.drop( item, Dungeon.hero.pos ).sprite.drop(); + } + WndSmith.this.hide(); + } + }; + btnConfirm.setRect(0, height+2, width/2-1, 16); + add(btnConfirm); + + RedButton btnCancel = new RedButton(Messages.get(WndSadGhost.class, "cancel")){ + @Override + protected void onClick() { + RewardWindow.this.hide(); + } + }; + btnCancel.setRect(btnConfirm.right()+2, height+2, btnConfirm.width(), 16); + add(btnCancel); + + resize(width, (int)btnCancel.bottom()); + } + } + + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmithOld.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmithOld.java deleted file mode 100644 index 6854906c0..000000000 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBlacksmithOld.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2023 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.windows; - -import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Belongings; -import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith; -import com.shatteredpixel.shatteredpixeldungeon.items.Item; -import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; -import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; -import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; -import com.shatteredpixel.shatteredpixeldungeon.ui.ItemButton; -import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; -import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; -import com.shatteredpixel.shatteredpixeldungeon.ui.Window; - -//pre-v2.2.0 -public class WndBlacksmithOld extends Window { - - private static final int BTN_SIZE = 36; - private static final float GAP = 2; - private static final float BTN_GAP = 10; - private static final int WIDTH = 116; - - private ItemButton btnPressed; - - private ItemButton btnItem1; - private ItemButton btnItem2; - private RedButton btnReforge; - - public WndBlacksmithOld(Blacksmith troll, Hero hero ) { - - super(); - - IconTitle titlebar = new IconTitle(); - titlebar.icon( troll.sprite() ); - titlebar.label( Messages.titleCase( troll.name() ) ); - titlebar.setRect( 0, 0, WIDTH, 0 ); - add( titlebar ); - - RenderedTextBlock message = PixelScene.renderTextBlock( Messages.get(this, "prompt"), 6 ); - message.maxWidth( WIDTH); - message.setPos(0, titlebar.bottom() + GAP); - add( message ); - - btnItem1 = new ItemButton() { - @Override - protected void onClick() { - btnPressed = btnItem1; - GameScene.selectItem( itemSelector ); - } - }; - btnItem1.setRect( (WIDTH - BTN_GAP) / 2 - BTN_SIZE, message.top() + message.height() + BTN_GAP, BTN_SIZE, BTN_SIZE ); - add( btnItem1 ); - - btnItem2 = new ItemButton() { - @Override - protected void onClick() { - btnPressed = btnItem2; - GameScene.selectItem( itemSelector ); - } - }; - btnItem2.setRect( btnItem1.right() + BTN_GAP, btnItem1.top(), BTN_SIZE, BTN_SIZE ); - add( btnItem2 ); - - btnReforge = new RedButton( Messages.get(this, "reforge") ) { - @Override - protected void onClick() { - Blacksmith.upgrade( btnItem1.item(), btnItem2.item() ); - hide(); - } - }; - btnReforge.enable( false ); - btnReforge.setRect( 0, btnItem1.bottom() + BTN_GAP, WIDTH, 20 ); - add( btnReforge ); - - - resize( WIDTH, (int)btnReforge.bottom() ); - } - - protected WndBag.ItemSelector itemSelector = new WndBag.ItemSelector() { - - @Override - public String textPrompt() { - return Messages.get(WndBlacksmithOld.class, "select"); - } - - @Override - public Class preferredBag(){ - return Belongings.Backpack.class; - } - - @Override - public boolean itemSelectable(Item item) { - return item.isUpgradable(); - } - - @Override - public void onSelect( Item item ) { - if (item != null && btnPressed.parent != null) { - btnPressed.item( item ); - - if (btnItem1.item() != null && btnItem2.item() != null) { - String result = Blacksmith.verify( btnItem1.item(), btnItem2.item() ); - if (result != null) { - GameScene.show( new WndMessage( result ) ); - btnReforge.enable( false ); - } else { - btnReforge.enable( true ); - } - } - } - } - }; - -}