diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 518eecad9..67eb51195 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -273,6 +273,16 @@ actors.buffs.momentum.resting_desc=As he moves, the Freerunner builds momentum, 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.monkenergy$monkability$flurry.name=flurry of blows +actors.buffs.monkenergy$monkability$flurry.desc=An instant strike that deals X-Y damage and ignores armor. This ability has no cooldown if the Monk just attacked normally or with a weapon ability. +actors.buffs.monkenergy$monkability$dash.name=dash +actors.buffs.monkenergy$monkability$dash.desc=An instant dash up to 2 tiles away. This ability can go over hazards, but not through enemies or walls. +actors.buffs.monkenergy$monkability$focus.name=focus +actors.buffs.monkenergy$monkability$focus.desc=The monk takes a turn to focus, letting them dodge the next physical attack made against them within 20 turns. +actors.buffs.monkenergy$monkability$dragonkick.name=dragon kick +actors.buffs.monkenergy$monkability$dragonkick.desc=A devastating kick that deals X-Y damage and ignores armor. The force of the kick is so strong that the target is knocked away and paralyzed for 10 turns. +actors.buffs.monkenergy$monkability$meditate.name=meditate +actors.buffs.monkenergy$monkability$meditate.desc=The Monk focuses energy into her body for 5 turns. This clears most negative effects and restores charge to her magical items. actors.buffs.ooze.name=caustic ooze actors.buffs.ooze.heromsg=Caustic ooze eats your flesh. Wash it away! diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index 81cda877c..eb89fa8dd 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -163,6 +163,9 @@ windows.wndkeybindings$wndchangebinding.cant_unbind=You must have at least one k windows.wndkeybindings$wndchangebinding.confirm=Confirm windows.wndkeybindings$wndchangebinding.cancel=Cancel +windows.wndmonkabilities.title=choose an ability +windows.wndmonkabilities.energycost=(%d energy) + windows.wndquickbag.title=quick-use an item windows.wndranking.error=Unable to load additional information 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 index f7f543554..4f5632128 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/MonkEnergy.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/MonkEnergy.java @@ -21,20 +21,28 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; +import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; 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.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.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.ui.ActionIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.shatteredpixel.shatteredpixeldungeon.windows.WndMonkAbilities; import com.watabou.noosa.Image; +import com.watabou.noosa.audio.Sample; import com.watabou.utils.Bundle; +import com.watabou.utils.Callback; public class MonkEnergy extends Buff implements ActionIndicator.Action { @@ -152,20 +160,157 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action { @Override public void doAction() { - energy -= 1; - cooldown = 3; - ActionIndicator.clearAction(this); - BuffIndicator.refreshHero(); - //GameScene.show(new WndMonk(this)); + GameScene.show(new WndMonkAbilities(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 + public static abstract class MonkAbility { + + public static MonkAbility[] abilities = new MonkAbility[]{ + new Flurry(), + new Dash(), + new Focus(), + new DragonKick(), + new Meditate() + }; + + public String name(){ + return Messages.get(this, "name"); + } + + public String desc(){ + return Messages.get(this, "desc"); + } + + public abstract int energyCost(); + public abstract int cooldown(); + + public String targetingPrompt(){ + return null; //return a string if uses targeting + } + + public abstract void doAbility(Hero hero, Integer target ); + + public static class Flurry extends MonkAbility { + + @Override + public int energyCost() { + return 1; + } + + @Override + public int cooldown() { + return 3; + } + + @Override + public String targetingPrompt() { + return "choose a location"; + } + + @Override + public void doAbility(Hero hero, Integer target) { + //TODO + } + } + + public static class Dash extends MonkAbility { + + @Override + public int energyCost() { + return 2; + } + + @Override + public int cooldown() { + return 3; //extra turn as no time is spend dashing + } + + @Override + public String targetingPrompt() { + return "choose a location"; + } + + @Override + public void doAbility(Hero hero, Integer target) { + if (target == null || target == -1){ + return; + } + + //TODO check conditions + + hero.busy(); + Sample.INSTANCE.play(Assets.Sounds.MISS); + hero.sprite.jump(hero.pos, target, 0, 0.1f, new Callback() { + @Override + public void call() { + if (Dungeon.level.map[hero.pos] == Terrain.OPEN_DOOR) { + Door.leave( hero.pos ); + } + hero.pos = target; + Dungeon.level.occupyCell(hero); + hero.next(); + } + }); + + //TODO decrement energy + + } + } + + public static class Focus extends MonkAbility { + + @Override + public int energyCost() { + return 3; + } + + @Override + public int cooldown() { + return 3; + } + + @Override + public void doAbility(Hero hero, Integer target) { + //TODO + } + + } + + public static class DragonKick extends MonkAbility { + + @Override + public int energyCost() { + return 4; + } + + @Override + public int cooldown() { + return 3; + } + + @Override + public void doAbility(Hero hero, Integer target) { + //TODO + } + } + + public static class Meditate extends MonkAbility { + + @Override + public int energyCost() { + return 5; + } + + @Override + public int cooldown() { + return 3; + } + + @Override + public void doAbility(Hero hero, Integer target) { + //TODO + } + } + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndMonkAbilities.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndMonkAbilities.java new file mode 100644 index 000000000..665593e6b --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndMonkAbilities.java @@ -0,0 +1,98 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2023 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.windows; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MonkEnergy; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; +import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.Window; + +public class WndMonkAbilities extends Window { + + private static final int WIDTH_P = 120; + private static final int WIDTH_L = 160; + + private static final int MARGIN = 2; + + public WndMonkAbilities( MonkEnergy energyBuff ){ + super(); + + int width = PixelScene.landscape() ? WIDTH_L : WIDTH_P; + + float pos = MARGIN; + RenderedTextBlock title = PixelScene.renderTextBlock(Messages.titleCase(Messages.get(this, "title")), 9); + title.hardlight(TITLE_COLOR); + title.setPos((width-title.width())/2, pos); + title.maxWidth(width - MARGIN * 2); + add(title); + + pos = title.bottom() + 3*MARGIN; + + for (MonkEnergy.MonkAbility abil : MonkEnergy.MonkAbility.abilities) { + String text = "_" + Messages.titleCase(abil.name()) + " " + Messages.get(this, "energycost", abil.energyCost()) + ":_ " + abil.desc(); + RedButton moveBtn = new RedButton(text, 6){ + @Override + protected void onClick() { + super.onClick(); + hide(); + if (abil.targetingPrompt() != null) { + abilityBeingUsed = abil; + GameScene.selectCell(listener); + } else { + abil.doAbility(Dungeon.hero, null); + } + } + }; + moveBtn.leftJustify = true; + moveBtn.multiline = true; + moveBtn.setSize(width, moveBtn.reqHeight()); + moveBtn.setRect(0, pos, width, moveBtn.reqHeight()); + moveBtn.enable(energyBuff.energy >= abil.energyCost()); + add(moveBtn); + pos = moveBtn.bottom() + MARGIN; + } + + resize(width, (int)pos); + + } + + MonkEnergy.MonkAbility abilityBeingUsed; + + private CellSelector.Listener listener = new CellSelector.Listener() { + + @Override + public void onSelect(Integer cell) { + abilityBeingUsed.doAbility(Dungeon.hero, cell); + } + + @Override + public String prompt() { + return abilityBeingUsed.targetingPrompt(); + } + }; + +}