diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 3956ef34e..9df265f03 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1514,6 +1514,8 @@ items.weapon.melee.flail.desc=A spiked ball attached to a handle by a length of items.weapon.melee.gauntlet.name=stone gauntlet items.weapon.melee.gauntlet.stats_desc=This is a very fast weapon. +items.weapon.melee.gauntlet.ability_name=combo strike +items.weapon.melee.gauntlet.ability_desc=The Duelist can perform a _combo strike_ with a stone gauntlet. This attack is guaranteed to hit and is instantaneous if the Duelist has already successfully attacked with melee or thrown weapons twice in the last 3 turns. items.weapon.melee.gauntlet.desc=This massive gauntlet is made of crimson fabric with heavy magical stone layered on top. The fabric tightens around you, making the thick stone plates almost like a second skin. Swinging such a heavy weapon requires strength, but adds tremendous force to your blows. items.weapon.melee.glaive.name=glaive @@ -1524,6 +1526,8 @@ items.weapon.melee.glaive.desc=A massive polearm consisting of a sword blade on items.weapon.melee.gloves.name=studded gloves items.weapon.melee.gloves.stats_desc=This is a very fast weapon. +items.weapon.melee.gloves.ability_name=combo strike +items.weapon.melee.gloves.ability_desc=The Duelist can perform a _combo strike_ with studded gloves. This attack is guaranteed to hit and is instantaneous if the Duelist has already successfully attacked with melee or thrown weapons twice in the last 5 turns. items.weapon.melee.gloves.desc=These studded gloves don't provide any real protection, but they act as a serviceable weapon while keeping the hands free. items.weapon.melee.greataxe.name=greataxe @@ -1629,6 +1633,8 @@ items.weapon.melee.runicblade.desc=A mysterious weapon from a distant land, with items.weapon.melee.sai.name=sai items.weapon.melee.sai.stats_desc=This is a very fast weapon. +items.weapon.melee.sai.ability_name=combo strike +items.weapon.melee.sai.ability_desc=The Duelist can perform a _combo strike_ with sai. This attack is guaranteed to hit and is instantaneous if the Duelist has already successfully attacked with melee or thrown weapons in the last 4 turns. items.weapon.melee.sai.desc=Two thin blades meant to be wielded in one hand each. Excellent for tearing down enemies with a flurry of cuts. items.weapon.melee.scimitar.name=scimitar diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index 02dae14fa..24bc1f478 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -116,6 +116,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Flail; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.RoundShield; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sai; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon; import com.shatteredpixel.shatteredpixeldungeon.journal.Document; import com.shatteredpixel.shatteredpixeldungeon.journal.Notes; @@ -444,6 +445,10 @@ public class Hero extends Char { Buff.affect( this, Combo.class ).hit( enemy ); } + if (hit && heroClass == HeroClass.DUELIST && wasEnemy){ + Buff.append( this, Sai.ComboStrikeTracker.class, Sai.ComboStrikeTracker.DURATION); + } + return hit; } @@ -1893,6 +1898,10 @@ public class Hero extends Char { Buff.affect( this, Combo.class ).hit( enemy ); } + if (hit && heroClass == HeroClass.DUELIST && wasEnemy){ + Buff.append( this, Sai.ComboStrikeTracker.class, Sai.ComboStrikeTracker.DURATION); + } + curAction = null; super.onAttackComplete(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gauntlet.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gauntlet.java index f49de77cd..82ae530ba 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gauntlet.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gauntlet.java @@ -22,6 +22,8 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; public class Gauntlet extends MeleeWeapon { @@ -41,4 +43,14 @@ public class Gauntlet extends MeleeWeapon { lvl*Math.round(0.5f*(tier+1)); //+3 per level, down from +6 } + @Override + public String targetingPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + protected void duelistAbility(Hero hero, Integer target) { + Sai.comboStrikeAbility(hero, target, 3, this); + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gloves.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gloves.java index 1e5966110..b09279baa 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gloves.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Gloves.java @@ -22,6 +22,8 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; public class Gloves extends MeleeWeapon { @@ -43,4 +45,14 @@ public class Gloves extends MeleeWeapon { lvl*Math.round(0.5f*(tier+1)); //+1 per level, down from +2 } + @Override + public String targetingPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + protected void duelistAbility(Hero hero, Integer target) { + Sai.comboStrikeAbility(hero, target, 5, this); + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sai.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sai.java index a40223062..8f14d716e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sai.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sai.java @@ -22,7 +22,21 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee; 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.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Callback; + +import java.util.ArrayList; +import java.util.HashSet; public class Sai extends MeleeWeapon { @@ -41,4 +55,63 @@ public class Sai extends MeleeWeapon { lvl*Math.round(0.5f*(tier+1)); //+2 per level, down from +4 } + @Override + public String targetingPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + protected void duelistAbility(Hero hero, Integer target) { + Sai.comboStrikeAbility(hero, target, 4, this); + } + + public static void comboStrikeAbility(Hero hero, Integer target, int comboTime, MeleeWeapon wep){ + if (target == null) { + return; + } + + Char enemy = Actor.findChar(target); + if (enemy == null || enemy == hero || hero.isCharmedBy(enemy) || !Dungeon.level.heroFOV[target]) { + GLog.w(Messages.get(wep, "ability_no_target")); + return; + } + + if (!hero.canAttack(enemy)){ + GLog.w(Messages.get(wep, "ability_bad_position")); + return; + } + + hero.sprite.attack(enemy.pos, new Callback() { + @Override + public void call() { + boolean hit = hero.attack(enemy, 1, 0, Char.INFINITE_ACCURACY); + wep.onAbilityUsed(hero); + + HashSet buffs = hero.buffs(ComboStrikeTracker.class); + int recentHits = 0; + for (Buff b : buffs){ + if (b.cooldown() >= (ComboStrikeTracker.DURATION - comboTime)){ + recentHits++; + } + } + + if (recentHits >= 2 && hit){ + for (Buff b : buffs){ + b.detach(); + } + Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG); + hero.next(); + } else { + hero.spendAndNext(hero.attackDelay()); + } + } + }); + } + + public static class ComboStrikeTracker extends FlavourBuff{ + + public static float DURATION = 5f; + + } + }