diff --git a/core/src/main/assets/interfaces/buffs.png b/core/src/main/assets/interfaces/buffs.png index 221feb021..5ad7e65cd 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 bdfd5ebf9..402cd6278 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 8b5295fd1..9ba875e11 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -270,6 +270,10 @@ actors.buffs.momentum.momentum_desc=As he moves, the Freerunner builds momentum, actors.buffs.momentum.running_desc=As he moves, the Freerunner builds momentum, which he can spend to start freerunning.\n\nWhile freerunning, the Freerunner moves at double speed and gains bonus evasion based on his level.\n\nTurns remaining: %d. actors.buffs.momentum.resting_desc=As he moves, the Freerunner builds momentum, which he can spend to start freerunning.\n\nThe Freerunner needs time to regain his stamina before building momentum again.\n\nTurns remaining: %d. +actors.buffs.monkenergy.name=energy +actors.buffs.monkenergy.desc=As she defeats enemies, the monk gains energy that she can use on a variety of abilities. Most enemies grant 1 energy when defeated, and the Monk does not lose energy over time.\n\nCurrent energy: %1$d/%2$d. +actors.buffs.monkenergy.desc_cooldown=The monk has recently used an ability, and must wait before using another.\n\nCurrent cooldown: %d turns. + actors.buffs.ooze.name=caustic ooze actors.buffs.ooze.heromsg=Caustic ooze eats your flesh. Wash it away! actors.buffs.ooze.ondeath=You melt away... diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java index 5ab86814f..a7cb3efad 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java @@ -165,6 +165,8 @@ public class Badges { BOSS_SLAIN_3_ASSASSIN, BOSS_SLAIN_3_SNIPER, BOSS_SLAIN_3_WARDEN, + BOSS_SLAIN_3_CHAMPION, + BOSS_SLAIN_3_MONK, BOSS_SLAIN_3_ALL_SUBCLASSES ( 105, true ), BOSS_CHALLENGE_3 ( 106 ), BOSS_CHALLENGE_4 ( 107 ), @@ -727,6 +729,8 @@ public class Badges { thirdBossSubclassBadges.put(HeroSubClass.FREERUNNER, Badge.BOSS_SLAIN_3_FREERUNNER); thirdBossSubclassBadges.put(HeroSubClass.SNIPER, Badge.BOSS_SLAIN_3_SNIPER); thirdBossSubclassBadges.put(HeroSubClass.WARDEN, Badge.BOSS_SLAIN_3_WARDEN); + thirdBossSubclassBadges.put(HeroSubClass.CHAMPION, Badge.BOSS_SLAIN_3_CHAMPION); + thirdBossSubclassBadges.put(HeroSubClass.MONK, Badge.BOSS_SLAIN_3_MONK); } public static void validateBossSlain() { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AllyBuff.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AllyBuff.java index c81984c43..a6620f1b5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AllyBuff.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/AllyBuff.java @@ -22,9 +22,11 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; 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.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; @@ -49,21 +51,27 @@ public abstract class AllyBuff extends Buff{ //for when applying an ally buff should also cause that enemy to give exp/loot as if they had died //consider that chars with the ally alignment do not drop items or award exp on death public static void affectAndLoot(Mob enemy, Hero hero, Class buffCls){ - boolean droppingLoot = enemy.alignment != Char.Alignment.ALLY; + boolean wasEnemy = enemy.alignment == Char.Alignment.ENEMY; Buff.affect(enemy, buffCls); - if (enemy.buff(buffCls) != null){ - if (droppingLoot) enemy.rollToDropLoot(); + if (enemy.buff(buffCls) != null && wasEnemy){ + enemy.rollToDropLoot(); + Statistics.enemiesSlain++; Badges.validateMonstersSlain(); Statistics.qualifiedForNoKilling = false; - if (enemy.EXP > 0 && hero.lvl <= enemy.maxLvl) { - hero.sprite.showStatus(CharSprite.POSITIVE, Messages.get(enemy, "exp", enemy.EXP)); - hero.earnExp(enemy.EXP, enemy.getClass()); - } else { - hero.earnExp(0, enemy.getClass()); + + AscensionChallenge.processEnemyKill(enemy); + + int exp = hero.lvl <= enemy.maxLvl ? enemy.EXP : 0; + if (exp > 0) { + hero.sprite.showStatus(CharSprite.POSITIVE, Messages.get(enemy, "exp", exp)); + } + hero.earnExp(exp, enemy.getClass()); + + if (hero.subClass == HeroSubClass.MONK){ + Buff.affect(hero, MonkEnergy.class).gainEnergy(enemy); } - if (droppingLoot) AscensionChallenge.processEnemyKill(enemy); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/MonkEnergy.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/MonkEnergy.java new file mode 100644 index 000000000..f7f543554 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/MonkEnergy.java @@ -0,0 +1,171 @@ +/* + * 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.actors.buffs; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Ghoul; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.RipperDemon; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Wraith; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogDzewa; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.ui.ActionIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.watabou.noosa.Image; +import com.watabou.utils.Bundle; + +public class MonkEnergy extends Buff implements ActionIndicator.Action { + + { + type = buffType.POSITIVE; + revivePersists = true; + } + + public float energy; + public int cooldown; + + @Override + public int icon() { + return BuffIndicator.MONK_ENERGY; + } + + @Override + public void tintIcon(Image icon) { + if (cooldown > 0){ + icon.hardlight(0.33f, 0.33f, 1f); + } else { + icon.resetColor(); + } + } + + @Override + public float iconFadePercent() { + return Math.max(0, (energyCap() - energy)/ energyCap()); + } + + @Override + public String iconTextDisplay() { + return Integer.toString((int)energy); + } + + @Override + public boolean act() { + if (cooldown > 0){ + cooldown--; + if (cooldown == 0 && energy >= 1){ + ActionIndicator.setAction(this); + } + BuffIndicator.refreshHero(); + } + + spend(TICK); + return true; + } + + @Override + public String desc() { + String desc = Messages.get(this, "desc", (int)energy, energyCap()); + if (cooldown > 0){ + desc += "\n\n" + Messages.get(this, "desc_cooldown", cooldown); + } + return desc; + } + + public static String ENERGY = "energy"; + public static String COOLDOWN = "cooldown"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(ENERGY, energy); + bundle.put(COOLDOWN, cooldown); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + energy = bundle.getFloat(ENERGY); + cooldown = bundle.getInt(COOLDOWN); + + if (energy >= 1 && cooldown == 0){ + ActionIndicator.setAction(this); + } + } + + public void gainEnergy(Mob enemy ){ + if (target.buff(LockedFloor.class) != null && !target.buff(LockedFloor.class).regenOn()){ + return; //to prevent farming boss minions + } + + //bosses and minibosses give extra energy, certain enemies give half, otherwise give 1 + if (Char.hasProp(enemy, Char.Property.BOSS)) energy += 5; + else if (Char.hasProp(enemy, Char.Property.MINIBOSS)) energy += 3; + else if (enemy instanceof Ghoul) energy += 0.5f; + else if (enemy instanceof RipperDemon) energy += 0.5f; + else if (enemy instanceof YogDzewa.Larva) energy += 0.5f; + else if (enemy instanceof Wraith) energy += 0.5f; + else energy += 1; + + energy = Math.min(energy, energyCap()); + + if (energy > 0 && cooldown == 0){ + ActionIndicator.setAction(this); + } + } + + //10 at base, 20 at level 30 + public int energyCap(){ + return Math.max(10, 5 + Dungeon.hero.lvl/2); + } + + @Override + public String actionName() { + return "TODO"; + } + + @Override + public Image actionIcon() { + return new HeroIcon(HeroSubClass.MONK); + } + + @Override + public void doAction() { + energy -= 1; + cooldown = 3; + ActionIndicator.clearAction(this); + BuffIndicator.refreshHero(); + //GameScene.show(new WndMonk(this)); + } + + public enum MonkAbility { + FLURRY_OF_BLOWS, //1 + CLEANSE, //Just part of meditate? + DASH, //2 or 3 energy? + UPPERCUT, //2 + FOCUS, //3 + DRAGON_KICK, //5 + MEDITATE //5 + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java index 2d137efff..0137e81d8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java @@ -79,7 +79,7 @@ public enum HeroClass { MAGE( HeroSubClass.BATTLEMAGE, HeroSubClass.WARLOCK ), ROGUE( HeroSubClass.ASSASSIN, HeroSubClass.FREERUNNER ), HUNTRESS( HeroSubClass.SNIPER, HeroSubClass.WARDEN ), - DUELIST( HeroSubClass.CHAMPION ); + DUELIST( HeroSubClass.CHAMPION, HeroSubClass.MONK ); private HeroSubClass[] subClasses; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index debf9a110..ef21c8c1c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -41,12 +41,14 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Haste; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Hunger; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MonkEnergy; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Preparation; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SoulMark; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; @@ -733,6 +735,10 @@ public abstract class Mob extends Char { Dungeon.hero.sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "exp", exp)); } Dungeon.hero.earnExp(exp, getClass()); + + if (Dungeon.hero.subClass == HeroSubClass.MONK){ + Buff.affect(Dungeon.hero, MonkEnergy.class).gainEnergy(this); + } } } } 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 2b20c139a..4beb6265c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -119,6 +119,7 @@ public class BuffIndicator extends Component { public static final int DUEL_BRAWL = 65; public static final int DUEL_XBOW = 66; public static final int CHALLENGE = 67; + public static final int MONK_ENERGY = 68; public static final int SIZE_SMALL = 7; public static final int SIZE_LARGE = 16;