v2.0.0: implemented the focus and dash monk abilities
This commit is contained in:
@@ -274,11 +274,16 @@ 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$flurry.desc=An instant strike that deals %1$d-%2$d damage and ignores armor. This ability has no cooldown if the Monk just attacked normally or with a weapon ability.
|
||||
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$focus.desc=The monk takes a turn to focus, letting her parry the next physical attack made against her within 30 turns.
|
||||
actors.buffs.monkenergy$monkability$focus$focusbuff.name=focused
|
||||
actors.buffs.monkenergy$monkability$focus$focusbuff.desc=The monk is focused on her surroundings, anticipating the next physical attack made against her. While focused, she is garunteed to parry the next incoming physical attack.\n\nTurns remaining: %s.
|
||||
actors.buffs.monkenergy$monkability$dash.name=dash
|
||||
actors.buffs.monkenergy$monkability$dash.prompt=Choose a location
|
||||
actors.buffs.monkenergy$monkability$dash.too_far=That location is too far away.
|
||||
actors.buffs.monkenergy$monkability$dash.blocked=There is something blocking that location.
|
||||
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$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
|
||||
@@ -1181,7 +1186,7 @@ actors.mobs.monk.def_verb=blocked
|
||||
actors.mobs.monk.parried=parried
|
||||
actors.mobs.monk.desc=These monks are fanatics, who have devoted themselves to protecting their king through physical might. So great is their devotion that they have totally surrendered their minds to their king, and now roam the dwarvern city like mindless zombies.\n\nMonks rely solely on the art of hand-to-hand combat, and are able to use their unarmed fists both for offense and defense. When they become focused, monks will parry the next physical attack used against them, even if it was otherwise guaranteed to hit. Monks build focus more quickly while on the move, and more slowly when in direct combat.
|
||||
actors.mobs.monk$focus.name=focused
|
||||
actors.mobs.monk$focus.desc=This monk is perfectly honed in on their target, and seem to be anticipating their moves before they make them.\n\nWhile focused, the next physical attack made against their character is guaranteed to miss, no matter what circumstances there are. Parrying this attack will spend the monk's focus, and they will need to build it up again to parry another attack. Monks build focus more quickly while they are moving.
|
||||
actors.mobs.monk$focus.desc=This monk is perfectly honed in on their target, and seem to be anticipating their moves before they make them.\n\nWhile focused, the next physical attack made against this character is guaranteed to miss, no matter what circumstances there are. Parrying this attack will spend the monk's focus, and they will need to build it up again to parry another attack. Monks build focus more quickly while they are moving.
|
||||
|
||||
actors.mobs.piranha.name=giant piranha
|
||||
actors.mobs.piranha.desc=These carnivorous fish are not natural inhabitants of underground pools. They were bred specifically to protect flooded treasure vaults.
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LifeLink;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LostInventory;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicalSleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Momentum;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MonkEnergy;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
@@ -323,7 +324,7 @@ public abstract class Char extends Actor {
|
||||
|
||||
return false;
|
||||
|
||||
} else if (hit( this, enemy, accMulti )) {
|
||||
} else if (hit( this, enemy, accMulti, false )) {
|
||||
|
||||
int dr = Math.round(enemy.drRoll() * AscensionChallenge.statModifier(enemy));
|
||||
|
||||
@@ -488,10 +489,10 @@ public abstract class Char extends Actor {
|
||||
public static int INFINITE_EVASION = 1_000_000;
|
||||
|
||||
final public static boolean hit( Char attacker, Char defender, boolean magic ) {
|
||||
return hit(attacker, defender, magic ? 2f : 1f);
|
||||
return hit(attacker, defender, magic ? 2f : 1f, magic);
|
||||
}
|
||||
|
||||
public static boolean hit( Char attacker, Char defender, float accMulti ) {
|
||||
public static boolean hit( Char attacker, Char defender, float accMulti, boolean magic ) {
|
||||
float acuStat = attacker.attackSkill( defender );
|
||||
float defStat = defender.defenseSkill( attacker );
|
||||
|
||||
@@ -500,6 +501,10 @@ public abstract class Char extends Actor {
|
||||
acuStat = INFINITE_ACCURACY;
|
||||
}
|
||||
|
||||
if (defender.buff(MonkEnergy.MonkAbility.Focus.FocusBuff.class) != null && !magic){
|
||||
defStat = INFINITE_EVASION;
|
||||
}
|
||||
|
||||
//if accuracy or evasion are large enough, treat them as infinite.
|
||||
//note that infinite evasion beats infinite accuracy
|
||||
if (defStat >= INFINITE_EVASION){
|
||||
|
||||
@@ -23,21 +23,26 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
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.Monk;
|
||||
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.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
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.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndMonkAbilities;
|
||||
import com.watabou.noosa.Image;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
@@ -141,6 +146,7 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
if (energy > 0 && cooldown == 0){
|
||||
ActionIndicator.setAction(this);
|
||||
}
|
||||
BuffIndicator.refreshHero();
|
||||
}
|
||||
|
||||
//10 at base, 20 at level 30
|
||||
@@ -148,6 +154,14 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
return Math.max(10, 5 + Dungeon.hero.lvl/2);
|
||||
}
|
||||
|
||||
public void abilityUsed( MonkAbility abil ){
|
||||
energy -= abil.energyCost();
|
||||
cooldown = abil.cooldown();
|
||||
if (cooldown > 0 || energy < 1){
|
||||
ActionIndicator.clearAction(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String actionName() {
|
||||
return "TODO";
|
||||
@@ -167,8 +181,8 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
|
||||
public static MonkAbility[] abilities = new MonkAbility[]{
|
||||
new Flurry(),
|
||||
new Dash(),
|
||||
new Focus(),
|
||||
new Dash(),
|
||||
new DragonKick(),
|
||||
new Meditate()
|
||||
};
|
||||
@@ -203,31 +217,15 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
}
|
||||
|
||||
@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
|
||||
public String desc() {
|
||||
//double hero unarmed damage
|
||||
//TODO maybe two hits at regular unarmed damage instead?
|
||||
return Messages.get(this, "desc", 2, 2*(Dungeon.hero.STR()-8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String targetingPrompt() {
|
||||
return "choose a location";
|
||||
return "choose a target";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -236,10 +234,103 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO check conditions
|
||||
//TODO check for target viability
|
||||
|
||||
//TODO add a buff that forces melee only (and no RoF!)
|
||||
|
||||
//check for can attack
|
||||
|
||||
//clear buff if can't
|
||||
|
||||
//do attack logic
|
||||
}
|
||||
}
|
||||
|
||||
public static class Focus extends MonkAbility {
|
||||
|
||||
@Override
|
||||
public int energyCost() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cooldown() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAbility(Hero hero, Integer target) {
|
||||
Buff.prolong(hero, FocusBuff.class, 30f);
|
||||
|
||||
Buff.affect(hero, MonkEnergy.class).abilityUsed(this);
|
||||
hero.spendAndNext(1f);
|
||||
}
|
||||
|
||||
public static class FocusBuff extends FlavourBuff {
|
||||
|
||||
{
|
||||
type = buffType.POSITIVE;
|
||||
announced = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
return BuffIndicator.MIND_VISION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tintIcon(Image icon) {
|
||||
icon.hardlight(0.25f, 1.5f, 1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float iconFadePercent() {
|
||||
return Math.max(0, (30 - visualcooldown()) / 30);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Dash extends MonkAbility {
|
||||
|
||||
@Override
|
||||
public int energyCost() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cooldown() {
|
||||
return 3; //1 less turn as no time is spent dashing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String targetingPrompt() {
|
||||
return Messages.get(this, "prompt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAbility(Hero hero, Integer target) {
|
||||
if (target == null || target == -1){
|
||||
return;
|
||||
}
|
||||
|
||||
if (Dungeon.level.distance(hero.pos, target) > 3){
|
||||
GLog.w(Messages.get(this, "too_far"));
|
||||
return;
|
||||
}
|
||||
|
||||
Ballistica dash = new Ballistica(hero.pos, target, Ballistica.PROJECTILE);
|
||||
|
||||
if (!dash.collisionPos.equals(target)
|
||||
|| Actor.findChar(target) != null
|
||||
|| (Dungeon.level.solid[target] && !Dungeon.level.passable[target])){
|
||||
GLog.w(Messages.get(this, "blocked"));
|
||||
return;
|
||||
}
|
||||
|
||||
hero.busy();
|
||||
Sample.INSTANCE.play(Assets.Sounds.MISS);
|
||||
hero.sprite.emitter().start(Speck.factory(Speck.JET), 0.01f, Math.round(4 + 2*Dungeon.level.trueDistance(hero.pos, target)));
|
||||
hero.sprite.jump(hero.pos, target, 0, 0.1f, new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
@@ -252,30 +343,10 @@ public class MonkEnergy extends Buff implements ActionIndicator.Action {
|
||||
}
|
||||
});
|
||||
|
||||
//TODO decrement energy
|
||||
|
||||
Buff.affect(hero, MonkEnergy.class).abilityUsed(this);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Levitation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LostInventory;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Momentum;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MonkEnergy;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.PhysicalEmpower;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Recharging;
|
||||
@@ -540,6 +541,14 @@ public class Hero extends Char {
|
||||
return Messages.get(Monk.class, "parried");
|
||||
}
|
||||
|
||||
if (buff(MonkEnergy.MonkAbility.Focus.FocusBuff.class) != null){
|
||||
buff(MonkEnergy.MonkAbility.Focus.FocusBuff.class).detach();
|
||||
if (sprite != null && sprite.visible) {
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_PARRY, 1, Random.Float(0.96f, 1.05f));
|
||||
}
|
||||
return Messages.get(Monk.class, "parried");
|
||||
}
|
||||
|
||||
if (buff(RoundShield.GuardTracker.class) != null){
|
||||
buff(RoundShield.GuardTracker.class).detach();
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT_PARRY, 1, Random.Float(0.96f, 1.05f));
|
||||
|
||||
@@ -176,7 +176,7 @@ public class RipperDemon extends Mob {
|
||||
public void call() {
|
||||
|
||||
if (leapVictim != null && alignment != leapVictim.alignment){
|
||||
if (hit(RipperDemon.this, leapVictim, Char.INFINITE_ACCURACY)) {
|
||||
if (hit(RipperDemon.this, leapVictim, Char.INFINITE_ACCURACY, false)) {
|
||||
Buff.affect(leapVictim, Bleeding.class).set(0.75f * damageRoll());
|
||||
leapVictim.sprite.flash();
|
||||
Sample.INSTANCE.play(Assets.Sounds.HIT);
|
||||
|
||||
Reference in New Issue
Block a user