diff --git a/core/src/main/assets/interfaces/buffs.png b/core/src/main/assets/interfaces/buffs.png index fab8b983d..980748a79 100644 Binary files a/core/src/main/assets/interfaces/buffs.png and b/core/src/main/assets/interfaces/buffs.png differ diff --git a/core/src/main/assets/interfaces/large_buffs.png b/core/src/main/assets/interfaces/large_buffs.png index 87385dd1e..2ac695a7d 100644 Binary files a/core/src/main/assets/interfaces/large_buffs.png and b/core/src/main/assets/interfaces/large_buffs.png differ diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 30626c2b8..0b479eee3 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -229,6 +229,9 @@ actors.buffs.haste.desc=Energy courses through your muscles, allowing you to run actors.buffs.healing.name=healing actors.buffs.healing.desc=A magical remedy is causing wounds to close and flesh to knit.\n\nEvery turn health will steadily regenerate until the healing effect expires. The amount of healing may fade over time.\n\nNext heal: %d.\n\nHealing remaining: %d. +actors.buffs.herodisguise.name=disguise +actors.buffs.herodisguise.desc=Illusory magic has altered your physical appearance! The effect is purely cosmetic, but feels very strange regardless.\n\nTurns of disguise remaining: %s. + actors.buffs.hex.name=hexed actors.buffs.hex.heromsg=You have been hexed! actors.buffs.hex.desc=Dark magic which saps focus, making the target slightly disoriented.\n\nHexing reduces accuracy and evasion by 20%%, making the target less effective in combat.\n\nTurns of hex remaining: %s. diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index ddde55438..57598cf1b 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1396,6 +1396,7 @@ items.wands.cursedwand.grass=Grass erupts around you! items.wands.cursedwand.fire=You smell burning... items.wands.cursedwand.transmogrify_wand=Your wand transmogrifies into a different item! items.wands.cursedwand.transmogrify_other=Your item transmogrifies into something different! +items.wands.cursedwand.disguise=Your appearance changes before your eyes! items.wands.damagewand.upgrade_stat_name_1=Magic Damage diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/HeroDisguise.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/HeroDisguise.java new file mode 100644 index 000000000..e36329da6 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/HeroDisguise.java @@ -0,0 +1,84 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2024 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.actors.buffs; + +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.HeroSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; + +public class HeroDisguise extends FlavourBuff { + + { + announced = true; + } + + private HeroClass cls = null; + + public static float DURATION = 1000f; + + public HeroClass getDisguise(){ + return cls; + } + + @Override + public int icon() { + return BuffIndicator.DISGUISE; + } + + @Override + public float iconFadePercent() { + return Math.max(0, (DURATION - visualcooldown()) / DURATION); + } + + @Override + public void fx(boolean on) { + if (target instanceof Hero && target.sprite instanceof HeroSprite){ + if (cls == null) { + do { + cls = Random.oneOf(HeroClass.values()); + } while (cls == ((Hero) target).heroClass); + } + + if (on) ((HeroSprite)target.sprite).disguise(cls); + else ((HeroSprite)target.sprite).disguise(((Hero) target).heroClass); + GameScene.updateAvatar(); + } + } + + private static final String CLASS = "class"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(CLASS, cls); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + cls = bundle.getEnum(CLASS, HeroClass.class); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java index 3463e2d62..255aeb2d3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/CursedWand.java @@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Frost; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.HeroDisguise; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Hex; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Recharging; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; @@ -92,7 +93,6 @@ public class CursedWand { boolean positiveOnly = user == Dungeon.hero && Random.Float() < WondrousResin.positiveCurseEffectChance(); CursedEffect effect = randomValidEffect(origin, user, bolt, positiveOnly); - //CursedEffect effect = new InterFloorTeleport(); effect.FX(origin, user, bolt, new Callback() { @Override @@ -526,6 +526,7 @@ public class CursedWand { VERY_RARE_EFFECTS.add(new SpawnGoldenMimic()); VERY_RARE_EFFECTS.add(new AbortRetryFail()); VERY_RARE_EFFECTS.add(new RandomTransmogrify()); + VERY_RARE_EFFECTS.add(new HeroShapeShift()); } public static CursedEffect randomVeryRareEffect(){ @@ -699,4 +700,26 @@ public class CursedWand { } } + public static class HeroShapeShift extends CursedEffect{ + + @Override + public boolean valid(Item origin, Char user, Ballistica bolt, boolean positiveOnly) { + return user instanceof Hero || Actor.findChar(bolt.collisionPos) instanceof Hero; + } + + @Override + public boolean effect(Item origin, Char user, Ballistica bolt, boolean positiveOnly) { + if (user instanceof Hero){ + Buff.affect(user, HeroDisguise.class, HeroDisguise.DURATION); + GLog.w( Messages.get(CursedWand.class, "disguise") ); + return true; + } else if (Actor.findChar(bolt.collisionPos) instanceof Hero){ + Buff.affect(Actor.findChar(bolt.collisionPos), HeroDisguise.class, HeroDisguise.DURATION); + GLog.w( Messages.get(CursedWand.class, "disguise") ); + return true; + } + return false; + } + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 96d92b765..74b3cee5e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -1179,11 +1179,15 @@ public class GameScene extends PixelScene { } public static void updateKeyDisplay(){ - if (scene != null) scene.menu.updateKeys(); + if (scene != null && scene.menu != null) scene.menu.updateKeys(); } public static void showlevelUpStars(){ - if (scene != null) scene.status.showStarParticles(); + if (scene != null && scene.status != null) scene.status.showStarParticles(); + } + + public static void updateAvatar(){ + if (scene != null && scene.status != null) scene.status.updateAvatar(); } public static void resetMap() { @@ -1613,7 +1617,7 @@ public class GameScene extends PixelScene { image = Icons.get(Icons.INFO); } else if (objects.get(0) instanceof Hero) { title = textLines.remove(0); - image = HeroSprite.avatar(((Hero) objects.get(0)).heroClass, ((Hero) objects.get(0)).tier()); + image = HeroSprite.avatar((Hero) objects.get(0)); } else if (objects.get(0) instanceof Mob) { title = textLines.remove(0); image = ((Mob) objects.get(0)).sprite(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java index ec714233a..bce52f5f5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.HeroDisguise; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; @@ -61,6 +62,11 @@ public class HeroSprite extends CharSprite { else die(); } + + public void disguise(HeroClass cls){ + texture( cls.spritesheet() ); + updateArmor(); + } public void updateArmor() { @@ -167,6 +173,14 @@ public class HeroSprite extends CharSprite { return tiers; } + + public static Image avatar( Hero hero ){ + if (hero.buff(HeroDisguise.class) != null){ + return avatar(hero.buff(HeroDisguise.class).getDisguise(), hero.tier()); + } else { + return avatar(hero.heroClass, hero.tier()); + } + } public static Image avatar( HeroClass cl, int armorTier ) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 0a628e6c9..946409887 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -120,6 +120,7 @@ public class BuffIndicator extends Component { public static final int MONK_ENERGY = 68; public static final int DUEL_COMBO = 69; public static final int DAZE = 70; + public static final int DISGUISE = 71; public static final int SIZE_SMALL = 7; public static final int SIZE_LARGE = 16; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 9892ccc63..a170c38dc 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -108,7 +108,7 @@ public class StatusPane extends Component { }; add(heroInfo); - avatar = HeroSprite.avatar( Dungeon.hero.heroClass, lastTier ); + avatar = HeroSprite.avatar( Dungeon.hero ); add( avatar ); talentBlink = 0; @@ -319,12 +319,16 @@ public class StatusPane extends Component { int tier = Dungeon.hero.tier(); if (tier != lastTier) { lastTier = tier; - avatar.copy( HeroSprite.avatar( Dungeon.hero.heroClass, tier ) ); + avatar.copy( HeroSprite.avatar( Dungeon.hero ) ); } counter.setSweep((1f - Actor.now()%1f)%1f); } + public void updateAvatar(){ + avatar.copy( HeroSprite.avatar( Dungeon.hero ) ); + } + public void alpha( float value ){ value = GameMath.gate(0, value, 1f); bg.alpha(value); 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 c88de62cc..9179138d0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java @@ -142,7 +142,7 @@ public class WndHero extends WndTabbed { Hero hero = Dungeon.hero; IconTitle title = new IconTitle(); - title.icon( HeroSprite.avatar(hero.heroClass, hero.tier()) ); + title.icon( HeroSprite.avatar(hero) ); if (hero.name().equals(hero.className())) title.label( Messages.get(this, "title", hero.lvl, hero.className() ).toUpperCase( Locale.ENGLISH ) ); else