v0.9.3: implemented the redesigned spectral blades ability
This commit is contained in:
parent
b20cc11dee
commit
3d0bb462c2
|
@ -334,13 +334,14 @@ actors.buffs.wellfed.desc=You feel quite satisfied and full.\n\nWhile well fed,
|
|||
|
||||
##abilities
|
||||
actors.hero.abilities.armorability.self_target=You can't target yourself!
|
||||
actors.hero.abilities.armorability.prompt=Choose a target
|
||||
actors.hero.abilities.armorability.no_target=There's nothing to target there!
|
||||
actors.hero.abilities.armorability.prompt=Choose a location to target
|
||||
|
||||
actors.hero.abilities.warrior.heroicleap.name=heroic leap
|
||||
actors.hero.abilities.warrior.heroicleap.desc=The Warrior performs a heroic leap towards a targeted location, slamming down to stun all neighbouring enemies. Consumes 35 charge.
|
||||
actors.hero.abilities.warrior.heroicleap.prompt=Choose direction to leap
|
||||
actors.hero.abilities.warrior.shockwave.name=shockwave
|
||||
actors.hero.abilities.warrior.shockwave.desc=The Warrior slams the ground and releases a shockwave in a conical AOE. Enemies caught in the shockwave are damaged and crippled. Comsumes 35 energy.
|
||||
actors.hero.abilities.warrior.shockwave.desc=The Warrior slams the ground and releases a shockwave in a conical AOE. Enemies caught in the shockwave are damaged and crippled. Consumes 35 energy.
|
||||
actors.hero.abilities.warrior.warrior3.name=???
|
||||
actors.hero.abilities.warrior.warrior3.desc=I haven't decided on this ability yet.
|
||||
actors.hero.abilities.mage.moltenearth.name=molten earth
|
||||
|
@ -351,14 +352,14 @@ actors.hero.abilities.mage.mage3.name=???
|
|||
actors.hero.abilities.mage.mage3.desc=I haven't decided on this ability yet.
|
||||
actors.hero.abilities.rogue.smokebomb.name=smoke bomb
|
||||
actors.hero.abilities.rogue.smokebomb.fov=You can only jump to an empty location in your field of view
|
||||
actors.hero.abilities.rogue.smokebomb.desc=The Rogue blinks to any nearby location which he can see, leaving a plume of smoke where he stood. This ability makes the rogue temporarily invisible, and blinds any enemies adjacent to his old location.
|
||||
actors.hero.abilities.rogue.smokebomb.desc=The Rogue blinks to any nearby location which he can see, leaving a plume of smoke where he stood. This ability makes the rogue temporarily invisible, and blinds any enemies adjacent to his old location. Consumes 35 charge.
|
||||
actors.hero.abilities.rogue.smokebomb.prompt=Choose a location to jump to
|
||||
actors.hero.abilities.rogue.rogue2.name=???
|
||||
actors.hero.abilities.rogue.rogue2.desc=I haven't decided on this ability yet.
|
||||
actors.hero.abilities.rogue.rogue3.name=???
|
||||
actors.hero.abilities.rogue.rogue3.desc=I haven't decided on this ability yet.
|
||||
actors.hero.abilities.huntress.spectralblades.name=spectral blades
|
||||
actors.hero.abilities.huntress.spectralblades.desc=The Huntress creates a fan of spectral blades. Each of these blades will target a single enemy in the huntress's field of view, inflicting damage depending on her currently equipped melee weapon.
|
||||
actors.hero.abilities.huntress.spectralblades.desc=The Huntress throws a spectral blade at a target, inflicting damage depending on her currently equipped melee weapon. Consumes 35 charge.
|
||||
actors.hero.abilities.huntress.huntress2.name=???
|
||||
actors.hero.abilities.huntress.huntress2.desc=I haven't decided on this ability yet.
|
||||
actors.hero.abilities.huntress.huntress3.name=???
|
||||
|
@ -647,12 +648,12 @@ actors.hero.talent.barkskin.desc=_+1:_ When stepping in grass, the Warden gains
|
|||
actors.hero.talent.shielding_dew.title=shielding dew
|
||||
actors.hero.talent.shielding_dew.desc=_+1:_ Dewdrops can shield the Warden when her health is full, up to _20% of her max HP_.\n\n_+2:_ Dewdrops can shield the Warden when her health is full, up to _40% of her max HP_.\n\n_+3:_ Dewdrops can shield the Warden when her health is full, up to _60% of her max HP_.actors.hero.talent.hearty_meal.title=hearty meal
|
||||
|
||||
actors.hero.talent.spectral_blades_1.title=TODO NAME
|
||||
actors.hero.talent.spectral_blades_1.desc=TODO DESC
|
||||
actors.hero.talent.spectral_blades_2.title=TODO NAME
|
||||
actors.hero.talent.spectral_blades_2.desc=TODO DESC
|
||||
actors.hero.talent.spectral_blades_3.title=TODO NAME
|
||||
actors.hero.talent.spectral_blades_3.desc=TODO DESC
|
||||
actors.hero.talent.fan_of_blades.title=fan of blades
|
||||
actors.hero.talent.fan_of_blades.desc=_+1:_ Spectral blades can hit up to _1 additional target_ for 50% damage. The target must be visible and within a _30 degree_ cone AOE.\n\n_+1:_ Spectral blades can hit up to _2 additional targets_ for 50% damage. The targets must be visible and within a _60 degree_ cone AOE.\n\n_+1:_ Spectral blades can hit up to _3 additional targets_ for 50% damage. The targets must be visible and within a _90 degree_ cone AOE.\n\n_+1:_ Spectral blades can hit up to _4 additional targets_ for 50% damage. The targets must be visible and within a _120 degree_ cone AOE.
|
||||
actors.hero.talent.projecting_blades.title=projecting blades
|
||||
actors.hero.talent.projecting_blades.desc=_+1:_ Spectral blades has _+25% accuracy_, and can penetrate up to _2 solid tiles_.\n\n_+2:_ Spectral blades has _+50% accuracy_, and can penetrate up to _4 solid tiles_.\n\n_+3:_ Spectral blades has _+75% accuracy_, and can penetrate up to _6 solid tiles_.\n\n_+4:_ Spectral blades has _+100% accuracy_, and can penetrate up to _8 solid tiles_.
|
||||
actors.hero.talent.spirit_blades.title=spirit blades
|
||||
actors.hero.talent.spirit_blades.desc=_+1:_ Spectral blades has a _25% chance_ to also use the enchantment on the spirit bow.\n\n_+2:_ Spectral blades has a _50% chance_ to also use the enchantment on the spirit bow.\n\n_+3:_ Spectral blades has a _75% chance_ to also use the enchantment on the spirit bow.\n\n_+4:_ Spectral blades has a _100% chance_ to also use the enchantment on the spirit bow.
|
||||
|
||||
actors.hero.talent.huntress_2_1.title=TODO NAME
|
||||
actors.hero.talent.huntress_2_1.desc=TODO DESC
|
||||
|
|
|
@ -1099,6 +1099,13 @@ public class Hero extends Char {
|
|||
|
||||
if (wep != null) damage = wep.proc( this, enemy, damage );
|
||||
|
||||
if (buff(Talent.SpiritBladesTracker.class) != null
|
||||
&& Random.Int(4) < pointsInTalent(Talent.SPIRIT_BLADES)){
|
||||
SpiritBow bow = belongings.getItem(SpiritBow.class);
|
||||
if (bow != null) damage = bow.proc( this, enemy, damage );
|
||||
buff(Talent.SpiritBladesTracker.class).detach();
|
||||
}
|
||||
|
||||
damage = Talent.onAttackProc( this, enemy, damage );
|
||||
|
||||
switch (subClass) {
|
||||
|
|
|
@ -130,7 +130,7 @@ public enum Talent {
|
|||
//Warden T3
|
||||
DURABLE_TIPS(110, 3), BARKSKIN(111, 3), SHIELDING_DEW(112, 3),
|
||||
//Spectral Blades T4
|
||||
SPECTRAL_BLADES_1(113, 4), SPECTRAL_BLADES_2(114, 4), SPECTRAL_BLADES_3(115, 4),
|
||||
FAN_OF_BLADES(113, 4), PROJECTING_BLADES(114, 4), SPIRIT_BLADES(115, 4),
|
||||
//??? T4
|
||||
HUNTRESS_2_1(116, 4), HUNTRESS_2_2(117, 4), HUNTRESS_2_3(118, 4),
|
||||
//??? T4
|
||||
|
@ -149,6 +149,7 @@ public enum Talent {
|
|||
public static class RejuvenatingStepsCooldown extends FlavourBuff{};
|
||||
public static class RejuvenatingStepsFurrow extends CounterBuff{};
|
||||
public static class SeerShotCooldown extends FlavourBuff{};
|
||||
public static class SpiritBladesTracker extends FlavourBuff{};
|
||||
|
||||
int icon;
|
||||
int maxPoints;
|
||||
|
|
|
@ -22,68 +22,137 @@
|
|||
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
|
||||
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.items.weapon.missiles.Shuriken;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.MissileSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Callback;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class SpectralBlades extends ArmorAbility {
|
||||
|
||||
@Override
|
||||
protected String targetingPrompt() {
|
||||
return Messages.get(this, "prompt");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||
armor.charge -= 35;
|
||||
if (target == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (Actor.findChar(target) == hero){
|
||||
GLog.w(Messages.get(this, "self_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
Ballistica b = new Ballistica(hero.pos, target, Ballistica.WONT_STOP);
|
||||
final HashSet<Char> targets = new HashSet<>();
|
||||
|
||||
Char enemy = findChar(b, hero, 2*hero.pointsInTalent(Talent.PROJECTING_BLADES), targets);
|
||||
|
||||
if (enemy == null){
|
||||
GLog.w(Messages.get(this, "no_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
targets.add(enemy);
|
||||
|
||||
if (hero.hasTalent(Talent.FAN_OF_BLADES)){
|
||||
ConeAOE cone = new ConeAOE(b, 30*hero.pointsInTalent(Talent.FAN_OF_BLADES));
|
||||
for (Ballistica ray : cone.rays){
|
||||
Char toAdd = findChar(ray, hero, 2*hero.pointsInTalent(Talent.PROJECTING_BLADES), targets);
|
||||
if (toAdd != null && hero.fieldOfView[toAdd.pos]){
|
||||
targets.add(toAdd);
|
||||
}
|
||||
}
|
||||
while (targets.size() > 1 + hero.pointsInTalent(Talent.FAN_OF_BLADES)){
|
||||
Char furthest = null;
|
||||
for (Char ch : targets){
|
||||
if (furthest == null){
|
||||
furthest = ch;
|
||||
} else if (Dungeon.level.trueDistance(enemy.pos, ch.pos) >
|
||||
Dungeon.level.trueDistance(enemy.pos, furthest.pos)){
|
||||
furthest = ch;
|
||||
}
|
||||
}
|
||||
targets.remove(furthest);
|
||||
}
|
||||
}
|
||||
|
||||
armor.charge -= chargeUse(hero);
|
||||
Item.updateQuickslot();
|
||||
|
||||
Item proto = new Shuriken();
|
||||
|
||||
final HashMap<Callback, Mob> targets = new HashMap<>();
|
||||
final HashSet<Callback> callbacks = new HashSet<>();
|
||||
|
||||
for (Mob mob : Dungeon.level.mobs) {
|
||||
if (Dungeon.level.distance(hero.pos, mob.pos) <= 12
|
||||
&& Dungeon.level.heroFOV[mob.pos]
|
||||
&& mob.alignment != Char.Alignment.ALLY) {
|
||||
|
||||
Callback callback = new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
hero.attack( targets.get( this ) );
|
||||
targets.remove( this );
|
||||
if (targets.isEmpty()) {
|
||||
Invisibility.dispel();
|
||||
hero.spendAndNext( hero.attackDelay() );
|
||||
}
|
||||
for (Char ch : targets) {
|
||||
Callback callback = new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
float dmgMulti = ch == enemy ? 1f : 0.5f;
|
||||
float accmulti = 1f + 0.25f*hero.pointsInTalent(Talent.PROJECTING_BLADES);
|
||||
if (hero.hasTalent(Talent.SPIRIT_BLADES)){
|
||||
Buff.affect(hero, Talent.SpiritBladesTracker.class, 0f);
|
||||
}
|
||||
};
|
||||
hero.attack( ch, dmgMulti, 0, accmulti );
|
||||
callbacks.remove( this );
|
||||
if (callbacks.isEmpty()) {
|
||||
Invisibility.dispel();
|
||||
hero.spendAndNext( hero.attackDelay() );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
((MissileSprite)hero.sprite.parent.recycle( MissileSprite.class )).
|
||||
reset( hero.sprite, mob.pos, proto, callback );
|
||||
((MissileSprite)hero.sprite.parent.recycle( MissileSprite.class )).
|
||||
reset( hero.sprite, ch.pos, proto, callback );
|
||||
|
||||
targets.put( callback, mob );
|
||||
callbacks.add( callback );
|
||||
}
|
||||
|
||||
hero.sprite.zap( enemy.pos );
|
||||
hero.busy();
|
||||
}
|
||||
|
||||
private Char findChar(Ballistica path, Hero hero, int wallPenetration, HashSet<Char> existingTargets){
|
||||
for (int cell : path.path){
|
||||
Char ch = Actor.findChar(cell);
|
||||
if (ch != null){
|
||||
if (ch == hero || existingTargets.contains(ch)){
|
||||
continue;
|
||||
} else if (ch.alignment != Char.Alignment.ALLY){
|
||||
return ch;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (Dungeon.level.solid[cell]){
|
||||
wallPenetration--;
|
||||
if (wallPenetration < 0){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targets.size() == 0) {
|
||||
GLog.w( Messages.get(this, "no_enemies") );
|
||||
return;
|
||||
}
|
||||
|
||||
hero.sprite.zap( hero.pos );
|
||||
hero.busy();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Talent[] talents() {
|
||||
return new Talent[]{Talent.SPECTRAL_BLADES_1, Talent.SPECTRAL_BLADES_2, Talent.SPECTRAL_BLADES_3, Talent.HEROIC_ENERGY};
|
||||
return new Talent[]{Talent.FAN_OF_BLADES, Talent.PROJECTING_BLADES, Talent.SPIRIT_BLADES, Talent.HEROIC_ENERGY};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user