v2.0.0: base implementation for Feint ability
This commit is contained in:
@@ -489,6 +489,12 @@ actors.hero.abilities.duelist.elementalstrike.name=elemental strike
|
||||
actors.hero.abilities.duelist.elementalstrike.short_desc=The Duelist performs an _elemental strike_, spreading an effect in a conical AOE based on her weapon enchantment.
|
||||
actors.hero.abilities.duelist.elementalstrike.desc=The Duelist strikes an enemy or location, performing a regular attack that's guaranteed to hit and spreading a magical effect that travels up to 3 tiles in a 65 degree cone. This magical effect varies based on the enchantment on the Duelist's primary weapon.
|
||||
actors.hero.abilities.duelist.elementalstrike.generic_desc=An elemental strike with no enchantment will release a small burst of magic, dealing 5-10 damage to all enemies in range.
|
||||
actors.hero.abilities.duelist.feint.name=feint
|
||||
actors.hero.abilities.duelist.feint.prompt=Choose a location to dash to
|
||||
actors.hero.abilities.duelist.feint.too_far=That location is not adjacent to you
|
||||
actors.hero.abilities.duelist.feint.bad_location=You can't move to that location
|
||||
actors.hero.abilities.duelist.feint.short_desc=The Duelist _feints_, faking an attack while dashing to an adjacent tile. Enemies will attack her afterimage, leaving them open to a counterattack.
|
||||
actors.hero.abilities.duelist.feint.desc=The Duelist fakes an attack while dashing to an adjacent tile, leaving behind a momentary afterimage of herself. Enemies that were attacking the Duelist will attack her afterimage instead.\n\nEnemies that attack the afterimage become confused, which cancels their next action and leaves them open to a surprise attack.
|
||||
|
||||
actors.hero.abilities.ratmogrify.name=ratmogrify
|
||||
actors.hero.abilities.ratmogrify.cant_transform=You can't ratmogrify that!
|
||||
@@ -904,7 +910,12 @@ actors.hero.talent.striking_force.desc=_+1:_ The power of elemental strike's eff
|
||||
actors.hero.talent.directed_power.title=directed power
|
||||
actors.hero.talent.directed_power.desc=_+1:_ The direct attack from elemental strike gains _+30% enchantment power_ for each enemy in range of elemental strike's effect, including the attack target.\n\n_+2:_ The direct attack from elemental strike gains _+60% enchantment power_ for each enemy in range of elemental strike's effect, including the attack target.\n\n_+3:_ The direct attack from elemental strike gains _+90% enchantment power_ for each enemy in range of elemental strike's effect, including the attack target.\n\n_+4:_ The direct attack from elemental strike gains _+120% enchantment power_ for each enemy in range of elemental strike's effect, including the attack target.
|
||||
|
||||
#third armor ability
|
||||
actors.hero.talent.feigned_retreat.title=feigned retreat
|
||||
actors.hero.talent.feigned_retreat.desc=_+1:_ If an enemy attacks the Duelist's afterimage, she gains _2 turns_ of haste.\n\n_+2:_ If an enemy attacks the Duelist's afterimage, she gains _4 turns_ of haste.\n\n_+3:_ If an enemy attacks the Duelist's afterimage, she gains _6 turns_ of haste.\n\n_+4:_ If an enemy attacks the Duelist's afterimage, she gains _8 turns_ of haste.
|
||||
actors.hero.talent.expose_weakness.title=expose weakness
|
||||
actors.hero.talent.expose_weakness.desc=_+1:_ Enemies that attack the Duelist's afterimage become vulnerable for _1 turn_.\n\n_+2:_ Enemies that attack the Duelist's afterimage become vulnerable for _2 turns_.\n\n_+3:_ Enemies that attack the Duelist's afterimage become vulnerable for _3 turns_.\n\n_+1:_ Enemies that attack the Duelist's afterimage become vulnerable for _4 turns_.
|
||||
actors.hero.talent.lasting_image.title=TODO
|
||||
actors.hero.talent.lasting_image.desc=specific mechanics TBD
|
||||
|
||||
#universal
|
||||
actors.hero.talent.heroic_energy.title=heroic energy
|
||||
|
||||
@@ -165,7 +165,7 @@ public enum Talent {
|
||||
//Elemental Strike T4
|
||||
ELEMENTAL_REACH(148, 4), STRIKING_FORCE(149, 4), DIRECTED_POWER(150, 4),
|
||||
//Duelist A3 T4
|
||||
DUELIST_A3_1(151, 4), DUELIST_A3_2(152, 4), DUELIST_A3_3(153, 4),
|
||||
FEIGNED_RETREAT(151, 4), EXPOSE_WEAKNESS(152, 4), LASTING_IMAGE(153, 4),
|
||||
|
||||
//universal T4
|
||||
HEROIC_ENERGY(26, 4), //See icon() and title() for special logic for this one
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist;
|
||||
|
||||
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.buffs.BlobImmunity;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor;
|
||||
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.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.MirrorSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.noosa.tweeners.AlphaTweener;
|
||||
import com.watabou.noosa.tweeners.Delayer;
|
||||
import com.watabou.utils.Callback;
|
||||
|
||||
public class Feint extends ArmorAbility {
|
||||
|
||||
{
|
||||
baseChargeUse = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
return HeroIcon.FEINT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String targetingPrompt() {
|
||||
return Messages.get(this, "prompt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int targetedPos(Char user, int dst) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||
if (target == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Dungeon.level.adjacent(hero.pos, target)){
|
||||
GLog.w(Messages.get(this, "too_far"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Dungeon.level.passable[target] || Actor.findChar(target) != null){
|
||||
GLog.w(Messages.get(this, "bad_location"));
|
||||
return;
|
||||
}
|
||||
|
||||
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.spendAndNext(1f);
|
||||
}
|
||||
});
|
||||
|
||||
AfterImage image = new AfterImage();
|
||||
image.pos = hero.pos;
|
||||
GameScene.add(image, 1);
|
||||
|
||||
int imageAttackPos;
|
||||
Char enemyTarget = TargetHealthIndicator.instance.target();
|
||||
if (enemyTarget != null && enemyTarget.alignment == Char.Alignment.ENEMY){
|
||||
imageAttackPos = enemyTarget.pos;
|
||||
} else {
|
||||
imageAttackPos = image.pos + (image.pos - target);
|
||||
}
|
||||
//do a purely visual attack
|
||||
hero.sprite.parent.add(new Delayer(0f){
|
||||
@Override
|
||||
protected void onComplete() {
|
||||
image.sprite.attack(imageAttackPos, new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
//do nothing, attack is purely visual
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (Mob m : Dungeon.level.mobs.toArray( new Mob[0] )){
|
||||
if (m.focusingHero() ||
|
||||
(m.alignment == Char.Alignment.ENEMY && m.state != m.PASSIVE && Dungeon.level.distance(m.pos, image.pos) <= 2)){
|
||||
m.aggro(image);
|
||||
}
|
||||
}
|
||||
|
||||
armor.charge -= chargeUse(hero);
|
||||
Item.updateQuickslot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Talent[] talents() {
|
||||
return new Talent[]{Talent.FEIGNED_RETREAT, Talent.EXPOSE_WEAKNESS, Talent.LASTING_IMAGE, Talent.HEROIC_ENERGY};
|
||||
}
|
||||
|
||||
public static class AfterImage extends Mob {
|
||||
|
||||
{
|
||||
spriteClass = AfterImageSprite.class;
|
||||
defenseSkill = 0;
|
||||
|
||||
properties.add(Property.IMMOVABLE);
|
||||
|
||||
alignment = Alignment.ALLY;
|
||||
state = PASSIVE;
|
||||
|
||||
HP = HT = 1;
|
||||
|
||||
//fades just before the hero's next action
|
||||
actPriority = Actor.HERO_PRIO+1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteract(Char c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
destroy();
|
||||
sprite.die();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill(Char enemy) {
|
||||
if (enemy instanceof Mob){
|
||||
((Mob) enemy).clearEnemy();
|
||||
}
|
||||
Buff.affect(enemy, FeintConfusion.class, 1);
|
||||
if (enemy.sprite != null) enemy.sprite.showLost();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc(Char enemy, int damage) {
|
||||
if (enemy instanceof Mob){
|
||||
((Mob) enemy).clearEnemy();
|
||||
}
|
||||
Buff.affect(enemy, FeintConfusion.class, 1f);
|
||||
if (enemy.sprite != null) enemy.sprite.showLost();
|
||||
return super.defenseProc(enemy, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
immunities.addAll(new BlobImmunity().immunities());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSprite sprite() {
|
||||
CharSprite s = super.sprite();
|
||||
((AfterImageSprite)s).updateArmor();
|
||||
return s;
|
||||
}
|
||||
|
||||
public static class FeintConfusion extends FlavourBuff {
|
||||
|
||||
}
|
||||
|
||||
public static class AfterImageSprite extends MirrorSprite {
|
||||
@Override
|
||||
public void updateArmor() {
|
||||
updateArmor(6); //we can assume heroic armor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetColor() {
|
||||
super.resetColor();
|
||||
alpha(0.6f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
//don't interrupt current animation to start fading
|
||||
//this ensures the face attack animation plays
|
||||
if (parent != null) {
|
||||
parent.add( new AlphaTweener( this, 0, 3f ) {
|
||||
@Override
|
||||
protected void onComplete() {
|
||||
AfterImageSprite.this.killAndErase();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ 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.hero.abilities.duelist.Feint;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
@@ -225,6 +226,13 @@ public abstract class Mob extends Char {
|
||||
|
||||
boolean enemyInFOV = enemy != null && enemy.isAlive() && fieldOfView[enemy.pos] && enemy.invisible <= 0;
|
||||
|
||||
//prevents action, but still updates enemy seen status
|
||||
if (buff(Feint.AfterImage.FeintConfusion.class) != null){
|
||||
enemySeen = enemyInFOV;
|
||||
spend( TICK );
|
||||
return true;
|
||||
}
|
||||
|
||||
return state.act( enemyInFOV, justAlerted );
|
||||
}
|
||||
|
||||
@@ -690,6 +698,12 @@ public abstract class Mob extends Char {
|
||||
state = HUNTING;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearEnemy(){
|
||||
enemy = null;
|
||||
enemySeen = false;
|
||||
if (state == HUNTING) state = WANDERING;
|
||||
}
|
||||
|
||||
public boolean isTargeting( Char ch){
|
||||
return enemy == ch;
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.MirrorImage;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.utils.PointF;
|
||||
|
||||
public class MirrorSprite extends MobSprite {
|
||||
|
||||
@@ -42,6 +43,15 @@ public class MirrorSprite extends MobSprite {
|
||||
@Override
|
||||
public void link( Char ch ) {
|
||||
super.link( ch );
|
||||
updateArmor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bloodBurstA(PointF from, int damage) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
public void updateArmor(){
|
||||
updateArmor( ((MirrorImage)ch).armTier );
|
||||
}
|
||||
|
||||
|
||||
@@ -21,49 +21,16 @@
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.PrismaticImage;
|
||||
import com.watabou.noosa.Game;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
|
||||
public class PrismaticSprite extends MobSprite {
|
||||
|
||||
private static final int FRAME_WIDTH = 12;
|
||||
private static final int FRAME_HEIGHT = 15;
|
||||
|
||||
public PrismaticSprite() {
|
||||
super();
|
||||
|
||||
texture( Dungeon.hero.heroClass.spritesheet() );
|
||||
updateArmor( 0 );
|
||||
idle();
|
||||
}
|
||||
|
||||
public class PrismaticSprite extends MirrorSprite {
|
||||
|
||||
@Override
|
||||
public void link( Char ch ) {
|
||||
super.link( ch );
|
||||
public void updateArmor() {
|
||||
updateArmor( ((PrismaticImage)ch).armTier );
|
||||
}
|
||||
|
||||
public void updateArmor( int tier ) {
|
||||
TextureFilm film = new TextureFilm( HeroSprite.tiers(), tier, FRAME_WIDTH, FRAME_HEIGHT );
|
||||
|
||||
idle = new Animation( 1, true );
|
||||
idle.frames( film, 0, 0, 0, 1, 0, 0, 1, 1 );
|
||||
|
||||
run = new Animation( 20, true );
|
||||
run.frames( film, 2, 3, 4, 5, 6, 7 );
|
||||
|
||||
die = new Animation( 20, false );
|
||||
die.frames( film, 0 );
|
||||
|
||||
attack = new Animation( 15, false );
|
||||
attack.frames( film, 13, 14, 15, 0 );
|
||||
|
||||
idle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class HeroIcon extends Image {
|
||||
public static final int SPIRIT_HAWK = 27;
|
||||
public static final int CHALLENGE = 28;
|
||||
public static final int ELEMENTAL_STRIKE= 29;
|
||||
public static final int DUELIST_3 = 30;
|
||||
public static final int FEINT = 30;
|
||||
public static final int RATMOGRIFY = 31;
|
||||
|
||||
public HeroIcon(HeroSubClass subCls){
|
||||
|
||||
Reference in New Issue
Block a user