v1.1.0: scroll of polymorph reworked into scroll of metamorphosis

This commit is contained in:
Evan Debenham 2021-11-28 21:20:03 -05:00
parent fea3cc4473
commit 816d5fcd0e
20 changed files with 473 additions and 122 deletions

View File

@ -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;

View File

@ -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<String> getKeys(){
return data.keySet();
}
public boolean getBoolean( String key ) {
return data.optBoolean( key );

View File

@ -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.

View File

@ -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(

View File

@ -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<LinkedHashMap<Talent, Integer>> talents = new ArrayList<>();
public LinkedHashMap<Talent, Talent> metamorphedTalents = new LinkedHashMap<>();
private int attackSkill = 10;
private int defenseSkill = 5;

View File

@ -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<LinkedHashMap<Talent, Integer>> talents ){
public static void initClassTalents( HeroClass cls, ArrayList<LinkedHashMap<Talent, Integer>> talents){
initClassTalents( cls, talents, new LinkedHashMap<>());
}
public static void initClassTalents( HeroClass cls, ArrayList<LinkedHashMap<Talent, Integer>> talents, LinkedHashMap<Talent, Talent> 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);

View File

@ -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 );
}
}

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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<Talent, Integer> 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<Talent, Integer> options = new LinkedHashMap<>();
Set<Talent> curTalentsAtTier = Dungeon.hero.talents.get(tier-1).keySet();
for (HeroClass cls : HeroClass.values()){
ArrayList<LinkedHashMap<Talent, Integer>> clsTalents = new ArrayList<>();
Talent.initClassTalents(cls, clsTalents);
Set<Talent> 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<Talent, Integer> 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);
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>
*/
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();
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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<Talent, Integer> tier : Dungeon.hero.talents){
if (tier.containsKey(replacing)){
LinkedHashMap<Talent, Integer> 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));
}

View File

@ -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<LinkedHashMap<Talent, Integer>> talents ) {
public TalentsPane( TalentButton.Mode mode, ArrayList<LinkedHashMap<Talent, Integer>> 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<Image> stars = new ArrayList<>();
public TalentTierPane(LinkedHashMap<Talent, Integer> talents, int tier, boolean canUpgrade){
public TalentTierPane(LinkedHashMap<Talent, Integer> 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();

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<LinkedHashMap<Talent, Integer>> 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);

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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());