diff --git a/SPD-classes/src/main/java/com/watabou/noosa/Visual.java b/SPD-classes/src/main/java/com/watabou/noosa/Visual.java index da0dd1068..61b760a42 100644 --- a/SPD-classes/src/main/java/com/watabou/noosa/Visual.java +++ b/SPD-classes/src/main/java/com/watabou/noosa/Visual.java @@ -154,6 +154,10 @@ public class Visual extends Gizmo { y + (height() - v.height())/2f ); } + + public void originToCenter() { + origin.set(width / 2, height / 2); + } public float width() { return width * scale.x; diff --git a/SPD-classes/src/main/java/com/watabou/utils/Bundle.java b/SPD-classes/src/main/java/com/watabou/utils/Bundle.java index c316e7447..95c08e9ac 100644 --- a/SPD-classes/src/main/java/com/watabou/utils/Bundle.java +++ b/SPD-classes/src/main/java/com/watabou/utils/Bundle.java @@ -39,6 +39,7 @@ import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -71,6 +72,10 @@ public class Bundle { public boolean contains( String key ) { return !data.isNull( key ); } + + public Set getKeys(){ + return data.keySet(); + } public boolean getBoolean( String key ) { return data.optBoolean( key ); diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index dd3751daf..b2b5bb820 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1012,15 +1012,18 @@ items.scrolls.exotic.scrollofenchantment.desc=This scroll will infuse a weapon o items.scrolls.exotic.scrollofforesight.name=scroll of foresight items.scrolls.exotic.scrollofforesight.desc=After reading this scroll, the detail of nearby terrain will be constantly fed to the reader's mind in crystal clarity. This effect lasts for a considerable amount of time, and will reveal all hidden doors or traps, making searching unnecessary. +items.scrolls.exotic.scrollofmetamorphosis.name=scroll of metamorphosis +items.scrolls.exotic.scrollofmetamorphosis.choose_desc=Choose a talent to metamorphose. +items.scrolls.exotic.scrollofmetamorphosis.replace_desc=Choose a new talent to replace your metamorphosed talent with. +items.scrolls.exotic.scrollofmetamorphosis.metamorphose_talent=metamorphose talent +items.scrolls.exotic.scrollofmetamorphosis.desc=This scroll contains powerful transmutation magic, which will apply to the caster instead of to an item. The magic of this scroll will let you select one talent, and replace it with an equivalent talent from a different hero class!\n\nThis effect can only apply to class talents, not talents gained from subclasses or armor abilities. Be careful, not all talents work for all heroes. + items.scrolls.exotic.scrollofmysticalenergy.name=scroll of mystical energy items.scrolls.exotic.scrollofmysticalenergy.desc=The raw magical power bound up in this parchment will, when released, charge a user's equipped artifacts over time. items.scrolls.exotic.scrollofpassage.name=scroll of passage items.scrolls.exotic.scrollofpassage.desc=The spell on this parchment instantly transports the reader to the nearest region entrance above them. Very handy for quickly getting to a shop. -items.scrolls.exotic.scrollofpolymorph.name=scroll of polymorph -items.scrolls.exotic.scrollofpolymorph.desc=This scroll contains powerful transmutation magic. When invoked, all enemies in the reader's sight will be transformed into magical sheep!\n\nThe transformation is permanent, eliminating all enemies affected. Powerful enemies will resist the effect though, and any items affected enemies were carrying are lost. - items.scrolls.exotic.scrollofprismaticimage.name=scroll of prismatic image items.scrolls.exotic.scrollofprismaticimage.desc=The incantation on this scroll will create a colorful illusory twin of the reader. This prismatic image acts as a weaker clone of the reader, with similar defence but lower hp and damage.\n\nThe prismatic image will show itself when enemies are present, and will attempt to defend the reader.\n\nIf a prismatic image already exists, using this scroll will fully heal it. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java index 2ba7cee7c..a9c5a5355 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java @@ -21,6 +21,7 @@ package com.shatteredpixel.shatteredpixeldungeon; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfMetamorphosis; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.TitleScene; @@ -61,6 +62,9 @@ public class ShatteredPixelDungeon extends Game { com.watabou.utils.Bundle.addAlias( com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic.PotionOfMastery.class, "com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic.PotionOfAdrenalineSurge" ); + com.watabou.utils.Bundle.addAlias( + ScrollOfMetamorphosis.class, + "com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfPolymorph" ); //v1.0.0 com.watabou.utils.Bundle.addAlias( diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 38b4898bd..80c1ac8e4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -147,6 +147,7 @@ import com.watabou.utils.Random; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; public class Hero extends Char { @@ -169,6 +170,7 @@ public class Hero extends Char { public HeroSubClass subClass = HeroSubClass.NONE; public ArmorAbility armorAbility = null; public ArrayList> talents = new ArrayList<>(); + public LinkedHashMap metamorphedTalents = new LinkedHashMap<>(); private int attackSkill = 10; private int defenseSkill = 5; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java index 895645889..bb66f08d8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java @@ -467,10 +467,14 @@ public enum Talent { public static final int MAX_TALENT_TIERS = 4; public static void initClassTalents( Hero hero ){ - initClassTalents( hero.heroClass, hero.talents ); + initClassTalents( hero.heroClass, hero.talents, hero.metamorphedTalents ); } - public static void initClassTalents( HeroClass cls, ArrayList> talents ){ + public static void initClassTalents( HeroClass cls, ArrayList> talents){ + initClassTalents( cls, talents, new LinkedHashMap<>()); + } + + public static void initClassTalents( HeroClass cls, ArrayList> talents, LinkedHashMap replacements ){ while (talents.size() < MAX_TALENT_TIERS){ talents.add(new LinkedHashMap<>()); } @@ -493,6 +497,9 @@ public enum Talent { break; } for (Talent talent : tierTalents){ + if (replacements.containsKey(talent)){ + talent = replacements.get(talent); + } talents.get(0).put(talent, 0); } tierTalents.clear(); @@ -513,6 +520,9 @@ public enum Talent { break; } for (Talent talent : tierTalents){ + if (replacements.containsKey(talent)){ + talent = replacements.get(talent); + } talents.get(1).put(talent, 0); } tierTalents.clear(); @@ -533,6 +543,9 @@ public enum Talent { break; } for (Talent talent : tierTalents){ + if (replacements.containsKey(talent)){ + talent = replacements.get(talent); + } talents.get(2).put(talent, 0); } tierTalents.clear(); @@ -621,9 +634,23 @@ public enum Talent { } bundle.put(TALENT_TIER+(i+1), tierBundle); } + + Bundle replacementsBundle = new Bundle(); + for (Talent t : hero.metamorphedTalents.keySet()){ + replacementsBundle.put(t.name(), hero.metamorphedTalents.get(t)); + } + bundle.put("replacements", replacementsBundle); } public static void restoreTalentsFromBundle( Bundle bundle, Hero hero ){ + //TODO restore replacements + if (bundle.contains("replacements")){ + Bundle replacements = bundle.getBundle("replacements"); + for (String key : replacements.getKeys()){ + hero.metamorphedTalents.put(Talent.valueOf(key), replacements.getEnum(key, Talent.class)); + } + } + if (hero.heroClass != null) initClassTalents(hero); if (hero.subClass != null) initSubclassTalents(hero); if (hero.armorAbility != null) initArmorTalents(hero); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/Transmuting.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/Transmuting.java index 5d522b45d..8d4773153 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/Transmuting.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/Transmuting.java @@ -22,9 +22,12 @@ package com.shatteredpixel.shatteredpixeldungeon.effects; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentIcon; import com.watabou.noosa.Game; +import com.watabou.noosa.Image; import com.watabou.noosa.ui.Component; public class Transmuting extends Component { @@ -39,8 +42,8 @@ public class Transmuting extends Component { private static final float ALPHA = 0.6f; - ItemSprite oldSprite; - ItemSprite newSprite; + Image oldSprite; + Image newSprite; private Char target; @@ -64,6 +67,22 @@ public class Transmuting extends Component { passed = 0; } + public Transmuting( Talent oldTalent, Talent newTalent ){ + oldSprite = new TalentIcon(oldTalent); + oldSprite.originToCenter(); + add(oldSprite); + newSprite = new TalentIcon(newTalent); + newSprite.originToCenter(); + add(newSprite); + + oldSprite.alpha(0f); + newSprite.alpha(0f); + + phase = Phase.FADE_IN; + duration = FADE_IN_TIME; + passed = 0; + } + @Override public void update() { super.update(); @@ -121,4 +140,15 @@ public class Transmuting extends Component { ch.sprite.parent.add( sprite ); } + public static void show( Char ch, Talent oldTalent, Talent newTalent ) { + + if (!ch.sprite.visible) { + return; + } + + Transmuting sprite = new Transmuting( oldTalent, newTalent ); + sprite.target = ch; + ch.sprite.parent.add( sprite ); + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ExoticScroll.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ExoticScroll.java index 720b586f5..35b5f6ff4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ExoticScroll.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ExoticScroll.java @@ -36,7 +36,6 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportat import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTerror; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTransmutation; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; -import com.shatteredpixel.shatteredpixeldungeon.items.stones.Runestone; import com.watabou.utils.Reflection; import java.util.ArrayList; @@ -81,8 +80,8 @@ public abstract class ExoticScroll extends Scroll { regToExo.put(ScrollOfMirrorImage.class, ScrollOfPrismaticImage.class); exoToReg.put(ScrollOfPrismaticImage.class, ScrollOfMirrorImage.class); - regToExo.put(ScrollOfTransmutation.class, ScrollOfPolymorph.class); - exoToReg.put(ScrollOfPolymorph.class, ScrollOfTransmutation.class); + regToExo.put(ScrollOfTransmutation.class, ScrollOfMetamorphosis.class); + exoToReg.put(ScrollOfMetamorphosis.class, ScrollOfTransmutation.class); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java new file mode 100644 index 000000000..a8a22190b --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfMetamorphosis.java @@ -0,0 +1,258 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2021 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.items.scrolls.exotic; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Sheep; +import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; +import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.effects.Transmuting; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.InventoryScroll; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; +import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.Window; +import com.shatteredpixel.shatteredpixeldungeon.windows.IconTitle; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Random; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Set; + +//TODO currently lots of talents that do nothing +public class ScrollOfMetamorphosis extends ExoticScroll { + + { + icon = ItemSpriteSheet.Icons.SCROLL_METAMORPH; + } + + protected static boolean identifiedByUse = false; + + @Override + public void doRead() { + if (!isKnown()) { + identify(); + identifiedByUse = true; + } else { + identifiedByUse = false; + } + GameScene.show(new WndMetamorphChoose()); + } + + public static void onMetamorph( Talent oldTalent, Talent newTalent ){ + ((ScrollOfMetamorphosis) curItem).readAnimation(); + Sample.INSTANCE.play( Assets.Sounds.READ ); + curUser.sprite.emitter().start(Speck.factory(Speck.CHANGE), 0.2f, 10); + Transmuting.show(curUser, oldTalent, newTalent); + } + + private void confirmCancelation( Window chooseWindow ) { + GameScene.show( new WndOptions(new ItemSprite(this), + Messages.titleCase(name()), + Messages.get(InventoryScroll.class, "warning"), + Messages.get(InventoryScroll.class, "yes"), + Messages.get(InventoryScroll.class, "no") ) { + @Override + protected void onSelect( int index ) { + switch (index) { + case 0: + curUser.spendAndNext( TIME_TO_READ ); + identifiedByUse = false; + chooseWindow.hide(); + break; + case 1: + //do nothing + break; + } + } + public void onBackPressed() {} + } ); + } + + public static class WndMetamorphChoose extends Window { + + public static WndMetamorphChoose INSTANCE; + + public WndMetamorphChoose(){ + super(); + + INSTANCE = this; + + float top = 0; + + IconTitle title = new IconTitle( curItem ); + title.color( TITLE_COLOR ); + title.setRect(0, 0, 120, 0); + add(title); + + top = title.bottom() + 2; + + RenderedTextBlock text = PixelScene.renderTextBlock(Messages.get(ScrollOfMetamorphosis.class, "choose_desc"), 6); + text.maxWidth(120); + text.setPos(0, top); + add(text); + + top = text.bottom() + 2; + + TalentsPane p = new TalentsPane(TalentButton.Mode.METAMORPH_CHOOSE); + add(p); + p.setPos(0, top); + p.setSize(120, p.content().height()); + resize((int)p.width(), (int)p.bottom()); + p.setPos(0, top); + } + + @Override + public void hide() { + super.hide(); + INSTANCE = null; + } + + @Override + public void onBackPressed() { + + if (identifiedByUse){ + ((ScrollOfMetamorphosis)curItem).confirmCancelation(this); + } else { + super.onBackPressed(); + curItem.collect(); + } + } + } + + public static class WndMetamorphReplace extends Window { + + public static WndMetamorphReplace INSTANCE; + + public Talent replacing; + public int tier; + LinkedHashMap replaceOptions; + + //for window restoring + public WndMetamorphReplace(){ + super(); + + if (INSTANCE != null){ + replacing = INSTANCE.replacing; + tier = INSTANCE.tier; + replaceOptions = INSTANCE.replaceOptions; + INSTANCE = this; + setup(replacing, tier, replaceOptions); + } else { + hide(); + } + } + + public WndMetamorphReplace(Talent replacing, int tier){ + super(); + + INSTANCE = this; + + this.replacing = replacing; + this.tier = tier; + + LinkedHashMap options = new LinkedHashMap<>(); + Set curTalentsAtTier = Dungeon.hero.talents.get(tier-1).keySet(); + + for (HeroClass cls : HeroClass.values()){ + ArrayList> clsTalents = new ArrayList<>(); + Talent.initClassTalents(cls, clsTalents); + + Set clsTalentsAtTier = clsTalents.get(tier-1).keySet(); + boolean replacingIsInSet = false; + for (Talent talent : clsTalentsAtTier.toArray(new Talent[0])){ + if (talent == replacing){ + replacingIsInSet = true; + break; + } else { + if (curTalentsAtTier.contains(talent)){ + clsTalentsAtTier.remove(talent); + } + } + } + if (!replacingIsInSet && !clsTalentsAtTier.isEmpty()) { + options.put(Random.element(clsTalentsAtTier), Dungeon.hero.pointsInTalent(replacing)); + } + } + + replaceOptions = options; + setup(replacing, tier, options); + } + + private void setup(Talent replacing, int tier, LinkedHashMap replaceOptions){ + float top = 0; + + IconTitle title = new IconTitle( curItem ); + title.color( TITLE_COLOR ); + title.setRect(0, 0, 120, 0); + add(title); + + top = title.bottom() + 2; + + RenderedTextBlock text = PixelScene.renderTextBlock(Messages.get(ScrollOfMetamorphosis.class, "replace_desc"), 6); + text.maxWidth(120); + text.setPos(0, top); + add(text); + + top = text.bottom() + 2; + + TalentsPane.TalentTierPane optionsPane = new TalentsPane.TalentTierPane(replaceOptions, tier, TalentButton.Mode.METAMORPH_REPLACE); + add(optionsPane); + optionsPane.title.text(" "); + optionsPane.setPos(0, top); + optionsPane.setSize(120, optionsPane.height()); + resize((int)optionsPane.width(), (int)optionsPane.bottom()); + + resize(120, (int)optionsPane.bottom()); + } + + @Override + public void hide() { + super.hide(); + if (INSTANCE == this) { + INSTANCE = null; + } + } + + @Override + public void onBackPressed() { + ((ScrollOfMetamorphosis)curItem).confirmCancelation(this); + } + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPolymorph.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPolymorph.java deleted file mode 100644 index 49d5ea4f0..000000000 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/scrolls/exotic/ScrollOfPolymorph.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Pixel Dungeon - * Copyright (C) 2012-2015 Oleg Dolya - * - * Shattered Pixel Dungeon - * Copyright (C) 2014-2021 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.items.scrolls.exotic; - -import com.shatteredpixel.shatteredpixeldungeon.Assets; -import com.shatteredpixel.shatteredpixeldungeon.Dungeon; -import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Sheep; -import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; -import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; -import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; -import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; -import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; -import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; -import com.watabou.noosa.audio.Sample; -import com.watabou.utils.Random; - -public class ScrollOfPolymorph extends ExoticScroll { - - { - icon = ItemSpriteSheet.Icons.SCROLL_POLYMORPH; - } - - @Override - public void doRead() { - - new Flare( 5, 32 ).color( 0xFFFFFF, true ).show( curUser.sprite, 2f ); - Sample.INSTANCE.play( Assets.Sounds.READ ); - - for (Mob mob : Dungeon.level.mobs.toArray( new Mob[0] )) { - if (mob.alignment != Char.Alignment.ALLY && Dungeon.level.heroFOV[mob.pos]) { - if (!mob.properties().contains(Char.Property.BOSS) - && !mob.properties().contains(Char.Property.MINIBOSS)){ - Sheep sheep = new Sheep(); - sheep.lifespan = 10; - sheep.pos = mob.pos; - - //awards half exp for each sheep-ified mob - //50% chance to round up, 50% to round down - if (mob.EXP % 2 == 1) mob.EXP += Random.Int(2); - mob.EXP /= 2; - - mob.destroy(); - mob.sprite.killAndErase(); - Dungeon.level.mobs.remove(mob); - TargetHealthIndicator.instance.target(null); - GameScene.add(sheep); - CellEmitter.get(sheep.pos).burst(Speck.factory(Speck.WOOL), 4); - Sample.INSTANCE.play(Assets.Sounds.PUFF); - Sample.INSTANCE.play(Assets.Sounds.SHEEP); - } - } - } - identify(); - - readAnimation(); - - } - -} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java index e89a06747..4dd00da43 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSprite.java @@ -96,10 +96,6 @@ public class ItemSprite extends MovieClip { view(image, glowing); } - public void originToCenter() { - origin.set(width / 2, height / 2); - } - public void link() { link(heap); } 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 2ae8bb040..260af198e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java @@ -787,7 +787,7 @@ public class ItemSpriteSheet { public static final int SCROLL_CHALLENGE= EXOTIC_SCROLLS+8; public static final int SCROLL_PSIBLAST = EXOTIC_SCROLLS+9; public static final int SCROLL_DREAD = EXOTIC_SCROLLS+10; - public static final int SCROLL_POLYMORPH= EXOTIC_SCROLLS+11; + public static final int SCROLL_METAMORPH= EXOTIC_SCROLLS+11; static { assignIconRect( SCROLL_ENCHANT, 7, 7 ); assignIconRect( SCROLL_DIVINATE, 7, 6 ); @@ -800,7 +800,7 @@ public class ItemSpriteSheet { assignIconRect( SCROLL_CHALLENGE, 7, 7 ); assignIconRect( SCROLL_PSIBLAST, 5, 6 ); assignIconRect( SCROLL_DREAD, 5, 7 ); - assignIconRect( SCROLL_POLYMORPH, 7, 7 ); + assignIconRect( SCROLL_METAMORPH, 7, 7 ); } //16 free slots diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentButton.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentButton.java index bf8ae1155..b1d17e86d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentButton.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentButton.java @@ -26,6 +26,11 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.InventoryScroll; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfMetamorphosis; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoTalent; import com.watabou.gltextures.SmartTexture; @@ -39,6 +44,8 @@ import com.watabou.noosa.particles.Emitter; import com.watabou.noosa.ui.Button; import com.watabou.utils.Callback; +import java.util.LinkedHashMap; + public class TalentButton extends Button { public static final int WIDTH = 20; @@ -47,21 +54,28 @@ public class TalentButton extends Button { int tier; Talent talent; int pointsInTalent; - boolean upgradeEnabled; + Mode mode; TalentIcon icon; Image bg; ColorBlock fill; - public TalentButton(int tier, Talent talent, int points, boolean upgradeEnabled){ + public enum Mode { + INFO, + UPGRADE, + METAMORPH_CHOOSE, + METAMORPH_REPLACE + } + + public TalentButton(int tier, Talent talent, int points, Mode mode){ super(); hotArea.blockLevel = PointerArea.NEVER_BLOCK; this.tier = tier; this.talent = talent; this.pointsInTalent = points; - this.upgradeEnabled = upgradeEnabled; + this.mode = mode; bg.frame(20*(talent.maxPoints()-1), 0, WIDTH, HEIGHT); @@ -103,17 +117,94 @@ public class TalentButton extends Button { protected void onClick() { super.onClick(); - if (upgradeEnabled + if (mode == Mode.UPGRADE && Dungeon.hero != null && Dungeon.hero.isAlive() && Dungeon.hero.talentPointsAvailable(tier) > 0 && Dungeon.hero.pointsInTalent(talent) < talent.maxPoints()){ - ShatteredPixelDungeon.scene().addToFront(new WndInfoTalent(talent, pointsInTalent, new Callback() { + ShatteredPixelDungeon.scene().addToFront(new WndInfoTalent(talent, pointsInTalent, new WndInfoTalent.TalentButtonCallback() { + + @Override + public String prompt() { + return Messages.titleCase(Messages.get(WndInfoTalent.class, "upgrade")); + } + @Override public void call() { upgradeTalent(); } })); + } else if (mode == Mode.METAMORPH_CHOOSE && Dungeon.hero != null && Dungeon.hero.isAlive()) { + ShatteredPixelDungeon.scene().addToFront(new WndInfoTalent(talent, pointsInTalent, new WndInfoTalent.TalentButtonCallback() { + + @Override + public String prompt() { + return Messages.titleCase(Messages.get(ScrollOfMetamorphosis.class, "metamorphose_talent")); + } + + @Override + public void call() { + if (ScrollOfMetamorphosis.WndMetamorphChoose.INSTANCE != null){ + ScrollOfMetamorphosis.WndMetamorphChoose.INSTANCE.hide(); + } + GameScene.show(new ScrollOfMetamorphosis.WndMetamorphReplace(talent, tier)); + } + })); + } else if (mode == Mode.METAMORPH_REPLACE && Dungeon.hero != null && Dungeon.hero.isAlive()) { + ShatteredPixelDungeon.scene().addToFront(new WndInfoTalent(talent, pointsInTalent, new WndInfoTalent.TalentButtonCallback() { + + @Override + public String prompt() { + return Messages.titleCase(Messages.get(ScrollOfMetamorphosis.class, "metamorphose_talent")); + } + + @Override + public void call() { + Talent replacing = ScrollOfMetamorphosis.WndMetamorphReplace.INSTANCE.replacing; + + for (LinkedHashMap tier : Dungeon.hero.talents){ + if (tier.containsKey(replacing)){ + LinkedHashMap newTier = new LinkedHashMap<>(); + for (Talent t : tier.keySet()){ + if (t == replacing){ + newTier.put(talent, tier.get(replacing)); + + if (!Dungeon.hero.metamorphedTalents.containsValue(replacing)){ + Dungeon.hero.metamorphedTalents.put(replacing, talent); + + //if what we're replacing is already a value, we need to simplify the data structure + } else { + //a->b->a, we can just remove the entry entirely + if (Dungeon.hero.metamorphedTalents.get(talent) == replacing){ + Dungeon.hero.metamorphedTalents.remove(talent); + + //a->b->c, we need to simplify to a->c + } else { + for (Talent t2 : Dungeon.hero.metamorphedTalents.keySet()){ + if (Dungeon.hero.metamorphedTalents.get(t2) == replacing){ + Dungeon.hero.metamorphedTalents.put(t2, talent); + } + } + } + } + + } else { + newTier.put(t, tier.get(t)); + } + } + Dungeon.hero.talents.add(ScrollOfMetamorphosis.WndMetamorphReplace.INSTANCE.tier-1, newTier); + break; + } + } + + ScrollOfMetamorphosis.onMetamorph(replacing, talent); + + if (ScrollOfMetamorphosis.WndMetamorphReplace.INSTANCE != null){ + ScrollOfMetamorphosis.WndMetamorphReplace.INSTANCE.hide(); + } + + } + })); } else { ShatteredPixelDungeon.scene().addToFront(new WndInfoTalent(talent, pointsInTalent, null)); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentsPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentsPane.java index ff5adcc14..311d6347a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentsPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TalentsPane.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndInfoTalent; import com.watabou.noosa.ColorBlock; import com.watabou.noosa.Image; import com.watabou.noosa.ui.Component; @@ -44,16 +45,16 @@ public class TalentsPane extends ScrollPane { ColorBlock blocker; RenderedTextBlock blockText; - public TalentsPane( boolean canUpgrade ) { - this( canUpgrade, Dungeon.hero.talents ); + public TalentsPane( TalentButton.Mode mode ) { + this( mode, Dungeon.hero.talents ); } - public TalentsPane( boolean canUpgrade, ArrayList> talents ) { + public TalentsPane( TalentButton.Mode mode, ArrayList> talents ) { super(new Component()); int tiersAvailable = 1; - if (!canUpgrade){ + if (mode == TalentButton.Mode.INFO){ if (!Badges.isUnlocked(Badges.Badge.LEVEL_REACHED_1)){ tiersAvailable = 1; } else if (!Badges.isUnlocked(Badges.Badge.LEVEL_REACHED_2) || !Badges.isUnlocked(Badges.Badge.BOSS_SLAIN_2)){ @@ -80,7 +81,7 @@ public class TalentsPane extends ScrollPane { for (int i = 0; i < Math.min(tiersAvailable, talents.size()); i++){ if (talents.get(i).isEmpty()) continue; - TalentTierPane pane = new TalentTierPane(talents.get(i), i+1, canUpgrade); + TalentTierPane pane = new TalentTierPane(talents.get(i), i+1, mode); panes.add(pane); content.add(pane); @@ -156,7 +157,7 @@ public class TalentsPane extends ScrollPane { ArrayList stars = new ArrayList<>(); - public TalentTierPane(LinkedHashMap talents, int tier, boolean canUpgrade){ + public TalentTierPane(LinkedHashMap talents, int tier, TalentButton.Mode mode){ super(); this.tier = tier; @@ -165,11 +166,11 @@ public class TalentsPane extends ScrollPane { title.hardlight(Window.TITLE_COLOR); add(title); - if (canUpgrade) setupStars(); + if (mode == TalentButton.Mode.UPGRADE) setupStars(); buttons = new ArrayList<>(); for (Talent talent : talents.keySet()){ - TalentButton btn = new TalentButton(tier, talent, talents.get(talent), canUpgrade){ + TalentButton btn = new TalentButton(tier, talent, talents.get(talent), mode){ @Override public void upgradeTalent() { super.upgradeTalent(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java index 285a7e4fc..92a0e1d7a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java @@ -38,6 +38,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.StatusPane; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.watabou.gltextures.SmartTexture; @@ -189,7 +190,7 @@ public class WndHero extends WndTabbed { @Override protected void createChildren() { super.createChildren(); - pane = new TalentsPane(true); + pane = new TalentsPane(TalentButton.Mode.UPGRADE); add(pane); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHeroInfo.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHeroInfo.java index d2b89de96..9806d1713 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHeroInfo.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHeroInfo.java @@ -34,6 +34,7 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.watabou.noosa.Game; import com.watabou.noosa.Image; @@ -231,7 +232,7 @@ public class WndHeroInfo extends WndTabbed { Talent.initClassTalents(cls, talents); talents.get(2).clear(); //we show T3 talents with subclasses - talentPane = new TalentsPane(false, talents); + talentPane = new TalentsPane(TalentButton.Mode.INFO, talents); add(talentPane); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoArmorAbility.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoArmorAbility.java index 3602f9575..73c432d2f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoArmorAbility.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoArmorAbility.java @@ -7,6 +7,7 @@ import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.watabou.noosa.Image; @@ -21,7 +22,7 @@ public class WndInfoArmorAbility extends WndTitledMessage { ArrayList> talentList = new ArrayList<>(); Talent.initArmorTalents(ability, talentList); - TalentsPane.TalentTierPane talentPane = new TalentsPane.TalentTierPane(talentList.get(3), 4, false); + TalentsPane.TalentTierPane talentPane = new TalentsPane.TalentTierPane(talentList.get(3), 4, TalentButton.Mode.INFO); talentPane.title.text( Messages.titleCase(Messages.get(WndHeroInfo.class, "talents"))); talentPane.setRect(0, height + 5, width, talentPane.height()); add(talentPane); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoSubclass.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoSubclass.java index 434936c2d..96561114c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoSubclass.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoSubclass.java @@ -5,6 +5,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.shatteredpixel.shatteredpixeldungeon.windows.WndHeroInfo; import com.shatteredpixel.shatteredpixeldungeon.windows.WndTitledMessage; @@ -21,7 +22,7 @@ public class WndInfoSubclass extends WndTitledMessage { Talent.initClassTalents(cls, talentList); Talent.initSubclassTalents(subCls, talentList); - TalentsPane.TalentTierPane talentPane = new TalentsPane.TalentTierPane(talentList.get(2), 3, false); + TalentsPane.TalentTierPane talentPane = new TalentsPane.TalentTierPane(talentList.get(2), 3, TalentButton.Mode.INFO); talentPane.title.text( Messages.titleCase(Messages.get(WndHeroInfo.class, "talents"))); talentPane.setRect(0, height + 5, width, talentPane.height()); add(talentPane); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoTalent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoTalent.java index 316ad4ea3..0504a458f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoTalent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoTalent.java @@ -37,7 +37,7 @@ public class WndInfoTalent extends Window { private static final int WIDTH = 120; - public WndInfoTalent(Talent talent, int points, Callback onUpgradeButton){ + public WndInfoTalent(Talent talent, int points, TalentButtonCallback buttonCallback){ super(); IconTitle titlebar = new IconTitle(); @@ -58,21 +58,27 @@ public class WndInfoTalent extends Window { resize( WIDTH, (int)(txtInfo.bottom() + GAP) ); - if (onUpgradeButton != null) { - RedButton upgrade = new RedButton( Messages.get(this, "upgrade") ) { + if (buttonCallback != null) { + RedButton button = new RedButton( buttonCallback.prompt() ) { @Override protected void onClick() { super.onClick(); hide(); - onUpgradeButton.call(); + buttonCallback.call(); } }; - upgrade.icon(Icons.get(Icons.TALENT)); - upgrade.setRect(0, txtInfo.bottom() + 2*GAP, WIDTH, 18); - add(upgrade); - resize( WIDTH, (int)upgrade.bottom()+1 ); + button.icon(Icons.get(Icons.TALENT)); + button.setRect(0, txtInfo.bottom() + 2*GAP, WIDTH, 18); + add(button); + resize( WIDTH, (int)button.bottom()+1 ); } } + public static abstract class TalentButtonCallback implements Callback { + + public abstract String prompt(); + + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java index 9c601bab6..ce49e9c89 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java @@ -38,6 +38,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.ItemSlot; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.watabou.noosa.ColorBlock; @@ -187,7 +188,7 @@ public class WndRanking extends WndTabbed { } Game.scene().addToFront( new Window(){ { - TalentsPane p = new TalentsPane(false); + TalentsPane p = new TalentsPane(TalentButton.Mode.INFO); add(p); p.setPos(0, 0); p.setSize(120, p.content().height());