v0.7.1: implemented upgradeable missile weapons!

- missile weapons now have damage scaling and can be upgraded (except darts)
- upgraded missile weapons gain 3x durability (stacking multiplicatively)
- missile weapons with more than 100 uses now last indefinitely
- ring of sharpshooting now works with damage scaling, rather than applying a flat +20% dmg per level
- bolas buffed. base damage up to 6-9, from 4-6
- shuriken adjusted. base damage up to 4-8, from 4-6. uses down to 5, from 10
- throwing stones now have 1/2 value, instead of 1 value.
This commit is contained in:
Evan Debenham 2018-11-13 21:12:46 -05:00
parent 24a22626ee
commit 5207ba4e90
17 changed files with 143 additions and 248 deletions

View File

@ -288,7 +288,7 @@ public class Item implements Bundlable {
} }
public boolean isSimilar( Item item ) { public boolean isSimilar( Item item ) {
return getClass() == item.getClass(); return level == item.level && getClass() == item.getClass();
} }
protected void onDetach(){} protected void onDetach(){}

View File

@ -30,9 +30,8 @@ public class RingOfSharpshooting extends Ring {
return new Aim(); return new Aim();
} }
//roughly in line with the boost a weapon gets from an upgrade public static int levelDamageBonus( Char target ){
public static float damageMultiplier( Char target ){ return getBonus(target, RingOfSharpshooting.Aim.class);
return 1f + 0.2f * getBonus(target, Aim.class);
} }
public static float durabilityMultiplier( Char target ){ public static float durabilityMultiplier( Char target ){

View File

@ -31,21 +31,14 @@ public class Bolas extends MissileWeapon {
{ {
image = ItemSpriteSheet.BOLAS; image = ItemSpriteSheet.BOLAS;
} tier = 3;
baseUses = 5;
@Override
public int min(int lvl) {
return 4;
} }
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return 6; return 3 * tier + //9 base, down from 15
} (tier == 1 ? 2*lvl : tier*lvl); //scaling unchanged
@Override
public int STRReq(int lvl) {
return 13;
} }
@Override @Override
@ -53,14 +46,4 @@ public class Bolas extends MissileWeapon {
Buff.prolong( defender, Cripple.class, Cripple.DURATION ); Buff.prolong( defender, Cripple.class, Cripple.DURATION );
return super.proc( attacker, defender, damage ); return super.proc( attacker, defender, damage );
} }
@Override
protected float durabilityPerUse() {
return super.durabilityPerUse()*2f;
}
@Override
public int price() {
return 18 * quantity;
}
} }

View File

@ -42,6 +42,7 @@ public class Boomerang extends MissileWeapon {
unique = true; unique = true;
bones = false; bones = false;
tier = 1;
} }
@Override @Override
@ -62,18 +63,6 @@ public class Boomerang extends MissileWeapon {
return 6 + //half the base damage of a tier-1 weapon return 6 + //half the base damage of a tier-1 weapon
2 * lvl;//scales the same as a tier 1 weapon 2 * lvl;//scales the same as a tier 1 weapon
} }
@Override
public int STRReq(int lvl) {
lvl = Math.max(0, lvl);
//strength req decreases at +1,+3,+6,+10,etc.
return 9 - (int)(Math.sqrt(8 * lvl + 1) - 1)/2;
}
@Override
public boolean isUpgradable() {
return true;
}
@Override @Override
public boolean isIdentified() { public boolean isIdentified() {

View File

@ -29,21 +29,8 @@ public class FishingSpear extends MissileWeapon {
{ {
image = ItemSpriteSheet.FISHING_SPEAR; image = ItemSpriteSheet.FISHING_SPEAR;
}
tier = 2;
@Override
public int min(int lvl) {
return 4;
}
@Override
public int max(int lvl) {
return 10;
}
@Override
public int STRReq(int lvl) {
return 11;
} }
@Override @Override
@ -53,10 +40,4 @@ public class FishingSpear extends MissileWeapon {
} }
return super.proc(attacker, defender, damage); return super.proc(attacker, defender, damage);
} }
@Override
public int price() {
return 12 * quantity;
}
} }

View File

@ -27,25 +27,8 @@ public class Javelin extends MissileWeapon {
{ {
image = ItemSpriteSheet.JAVELIN; image = ItemSpriteSheet.JAVELIN;
}
tier = 4;
@Override
public int min(int lvl) {
return 8;
}
@Override
public int max(int lvl) {
return 20;
}
@Override
public int STRReq(int lvl) {
return 15;
} }
@Override
public int price() {
return 24 * quantity;
}
} }

View File

@ -47,6 +47,8 @@ abstract public class MissileWeapon extends Weapon {
{ {
stackable = true; stackable = true;
levelKnown = true; levelKnown = true;
bones = true;
defaultAction = AC_THROW; defaultAction = AC_THROW;
usesTargeting = true; usesTargeting = true;
@ -56,12 +58,64 @@ abstract public class MissileWeapon extends Weapon {
protected static final float MAX_DURABILITY = 100; protected static final float MAX_DURABILITY = 100;
protected float durability = MAX_DURABILITY; protected float durability = MAX_DURABILITY;
protected int baseUses = 10;
public boolean holster; public boolean holster;
//used to reduce durability from the source weapon stack, rather than the one being thrown. //used to reduce durability from the source weapon stack, rather than the one being thrown.
protected MissileWeapon parent; protected MissileWeapon parent;
public int tier;
@Override
public int min() {
return Math.max(0, min( level() + RingOfSharpshooting.levelDamageBonus(Dungeon.hero) ));
}
@Override
public int min(int lvl) {
return 2 * tier + //base
(tier == 1 ? lvl : 2*lvl); //level scaling
}
@Override
public int max() {
return Math.max(0, max( level() + RingOfSharpshooting.levelDamageBonus(Dungeon.hero) ));
}
@Override
public int max(int lvl) {
return 5 * tier + //base
(tier == 1 ? 2*lvl : tier*lvl); //level scaling
}
public int STRReq(int lvl){
lvl = Math.max(0, lvl);
//strength req decreases at +1,+3,+6,+10,etc.
return (7 + tier * 2) - (int)(Math.sqrt(8 * lvl + 1) - 1)/2;
}
@Override
public Item upgrade() {
if (quantity > 1){
MissileWeapon left = (MissileWeapon) split(quantity - 1);
left.parent = null;
super.upgrade();
//deal with full inventory.
if (!left.collect()){
Dungeon.level.drop( left, Dungeon.hero.pos);
}
} else {
super.upgrade();
}
durability = MAX_DURABILITY;
return this;
}
@Override @Override
public ArrayList<String> actions( Hero hero ) { public ArrayList<String> actions( Hero hero ) {
ArrayList<String> actions = super.actions( hero ); ArrayList<String> actions = super.actions( hero );
@ -170,20 +224,21 @@ abstract public class MissileWeapon extends Weapon {
} }
protected float durabilityPerUse(){ protected float durabilityPerUse(){
float usage = MAX_DURABILITY/10f; float usages = baseUses * (float)(Math.pow(3, level()));
if (Dungeon.hero.heroClass == HeroClass.HUNTRESS) usage /= 1.5f; if (Dungeon.hero.heroClass == HeroClass.HUNTRESS) usages *= 1.5f;
if (holster) usage /= MagicalHolster.HOLSTER_DURABILITY_FACTOR; if (holster) usages *= MagicalHolster.HOLSTER_DURABILITY_FACTOR;
usage /= RingOfSharpshooting.durabilityMultiplier( Dungeon.hero ); usages *= RingOfSharpshooting.durabilityMultiplier( Dungeon.hero );
return usage; float usage = MAX_DURABILITY/usages;
//after 100 uses, items just last forever.
return usage >= (MAX_DURABILITY/100f) ? usage : 0;
} }
@Override @Override
public int damageRoll(Char owner) { public int damageRoll(Char owner) {
int damage = augment.damageFactor(super.damageRoll( owner )); int damage = augment.damageFactor(super.damageRoll( owner ));
damage = Math.round( damage * RingOfSharpshooting.damageMultiplier( owner ));
if (owner instanceof Hero && if (owner instanceof Hero &&
((Hero)owner).heroClass == HeroClass.HUNTRESS) { ((Hero)owner).heroClass == HeroClass.HUNTRESS) {
@ -237,11 +292,6 @@ abstract public class MissileWeapon extends Weapon {
return super.doPickUp(hero); return super.doPickUp(hero);
} }
@Override
public boolean isUpgradable() {
return false;
}
@Override @Override
public boolean isIdentified() { public boolean isIdentified() {
return true; return true;
@ -253,8 +303,9 @@ abstract public class MissileWeapon extends Weapon {
String info = desc(); String info = desc();
info += "\n\n" + Messages.get( MissileWeapon.class, "stats", info += "\n\n" + Messages.get( MissileWeapon.class, "stats",
Math.round(augment.damageFactor(min()) * RingOfSharpshooting.damageMultiplier( Dungeon.hero )), tier,
Math.round(augment.damageFactor(max()) * RingOfSharpshooting.damageMultiplier( Dungeon.hero )), Math.round(augment.damageFactor(min())),
Math.round(augment.damageFactor(max())),
STRReq()); STRReq());
if (STRReq() > Dungeon.hero.STR()) { if (STRReq() > Dungeon.hero.STR()) {
@ -284,12 +335,19 @@ abstract public class MissileWeapon extends Weapon {
info += " " + Messages.get(this, "uses_left", info += " " + Messages.get(this, "uses_left",
(int)Math.ceil(durability/durabilityPerUse()), (int)Math.ceil(durability/durabilityPerUse()),
(int)Math.ceil(MAX_DURABILITY/durabilityPerUse())); (int)Math.ceil(MAX_DURABILITY/durabilityPerUse()));
} else {
info += " " + Messages.get(this, "unlimited_uses");
} }
return info; return info;
} }
@Override
public int price() {
return 6 * tier * quantity * (level() + 1);
}
private static final String DURABILITY = "durability"; private static final String DURABILITY = "durability";
@Override @Override

View File

@ -29,21 +29,15 @@ public class Shuriken extends MissileWeapon {
{ {
image = ItemSpriteSheet.SHURIKEN; image = ItemSpriteSheet.SHURIKEN;
tier = 2;
baseUses = 5;
} }
@Override
public int min(int lvl) {
return 4;
}
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return 6; return 4 * tier + //8 base, down from 10
} (tier == 1 ? 2*lvl : tier*lvl); //scaling unchanged
@Override
public int STRReq(int lvl) {
return 11;
} }
@Override @Override
@ -51,9 +45,4 @@ public class Shuriken extends MissileWeapon {
if (owner instanceof Hero && ((Hero) owner).justMoved) return 0; if (owner instanceof Hero && ((Hero) owner).justMoved) return 0;
else return super.speedFactor(owner); else return super.speedFactor(owner);
} }
@Override
public int price() {
return 12 * quantity;
}
} }

View File

@ -28,31 +28,20 @@ public class ThrowingHammer extends MissileWeapon {
{ {
image = ItemSpriteSheet.THROWING_HAMMER; image = ItemSpriteSheet.THROWING_HAMMER;
tier = 5;
baseUses = 15;
sticky = false; sticky = false;
} }
@Override @Override
public int min(int lvl) { public int min(int lvl) {
return 8; return Math.round(1.6f * tier) + //8 base, down from 10
(tier == 1 ? lvl : 2*lvl); //scaling unchanged
} }
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return 20; return 4 * tier + //20 base, down from 25
} (tier-1) * lvl; //+4 per level, down from +5
@Override
public int STRReq(int lvl) {
return 17;
}
@Override
protected float durabilityPerUse() {
return super.durabilityPerUse()/1.5f;
}
@Override
public int price() {
return 30 * quantity;
} }
} }

View File

@ -26,7 +26,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfSharpshooting;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.watabou.utils.Random; import com.watabou.utils.Random;
@ -37,21 +36,14 @@ public class ThrowingKnife extends MissileWeapon {
bones = false; bones = false;
} tier = 1;
baseUses = 5;
@Override
public int min(int lvl) {
return 2;
} }
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return 6; return 6 * tier + //6 base, up from 5
} (tier == 1 ? 2*lvl : tier*lvl); //scaling unchanged
@Override
public int STRReq(int lvl) {
return 9;
} }
private Char enemy; private Char enemy;
@ -72,7 +64,6 @@ public class ThrowingKnife extends MissileWeapon {
int damage = augment.damageFactor(Random.NormalIntRange( int damage = augment.damageFactor(Random.NormalIntRange(
min() + Math.round(diff*0.75f), min() + Math.round(diff*0.75f),
max())); max()));
damage = Math.round(damage * RingOfSharpshooting.damageMultiplier( hero ));
int exStr = hero.STR() - STRReq(); int exStr = hero.STR() - STRReq();
if (exStr > 0 && hero.heroClass == HeroClass.HUNTRESS) { if (exStr > 0 && hero.heroClass == HeroClass.HUNTRESS) {
damage += Random.IntRange(0, exStr); damage += Random.IntRange(0, exStr);
@ -82,14 +73,4 @@ public class ThrowingKnife extends MissileWeapon {
} }
return super.damageRoll(owner); return super.damageRoll(owner);
} }
@Override
protected float durabilityPerUse() {
return super.durabilityPerUse()*2f;
}
@Override
public int price() {
return 6 * quantity;
}
} }

View File

@ -27,26 +27,8 @@ public class ThrowingSpear extends MissileWeapon {
{ {
image = ItemSpriteSheet.THROWING_SPEAR; image = ItemSpriteSheet.THROWING_SPEAR;
}
tier = 3;
@Override
public int min(int lvl) {
return 6;
}
@Override
public int max(int lvl) {
return 15;
}
@Override
public int STRReq(int lvl) {
return 13;
}
@Override
public int price() {
return 18 * quantity;
} }
} }

View File

@ -28,34 +28,21 @@ public class ThrowingStone extends MissileWeapon {
{ {
image = ItemSpriteSheet.THROWING_STONE; image = ItemSpriteSheet.THROWING_STONE;
sticky = false;
bones = false; bones = false;
tier = 1;
baseUses = 3;
sticky = false;
} }
@Override @Override
public int min(int lvl) { public int min(int lvl) {
return 1; return tier + //1 base, down from 2
} (tier == 1 ? lvl : 2*lvl); //scaling unchanged
@Override
public int max(int lvl) {
return 5;
}
@Override
public int STRReq(int lvl) {
return 9;
}
@Override
protected float durabilityPerUse() {
return super.durabilityPerUse()*3.34f;
} }
@Override @Override
public int price() { public int price() {
return quantity; return super.price()/2; //half normal value
} }
} }

View File

@ -31,21 +31,20 @@ public class Tomahawk extends MissileWeapon {
{ {
image = ItemSpriteSheet.TOMAHAWK; image = ItemSpriteSheet.TOMAHAWK;
tier = 4;
baseUses = 5;
} }
@Override @Override
public int min(int lvl) { public int min(int lvl) {
return 6; return Math.round(1.5f * tier) + //6 base, down from 8
2 * lvl; //scaling unchanged
} }
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return 15; return Math.round(3.75f * tier) + //15 base, down from 20
} (tier-1)*lvl; //+3 per level, down from +4
@Override
public int STRReq(int lvl) {
return 15;
} }
@Override @Override
@ -53,14 +52,4 @@ public class Tomahawk extends MissileWeapon {
Buff.affect( defender, Bleeding.class ).set( damage ); Buff.affect( defender, Bleeding.class ).set( damage );
return super.proc( attacker, defender, damage ); return super.proc( attacker, defender, damage );
} }
@Override
protected float durabilityPerUse() {
return super.durabilityPerUse()*2f;
}
@Override
public int price() {
return 24 * quantity;
}
} }

View File

@ -27,26 +27,8 @@ public class Trident extends MissileWeapon {
{ {
image = ItemSpriteSheet.TRIDENT; image = ItemSpriteSheet.TRIDENT;
}
tier = 5;
@Override
public int min(int lvl) {
return 10;
}
@Override
public int max(int lvl) {
return 25;
}
@Override
public int STRReq(int lvl) {
return 17;
}
@Override
public int price() {
return 30 * quantity;
} }
} }

View File

@ -34,21 +34,30 @@ public class Dart extends MissileWeapon {
{ {
image = ItemSpriteSheet.DART; image = ItemSpriteSheet.DART;
tier = 1;
} }
@Override @Override
public int min(int lvl) { public int min(int lvl) {
return bow != null ? 4 + bow.level() : 1; if (bow != null){
return 4 + //4 base
bow.level() + lvl; //+1 per level or bow level
} else {
return 1 + //1 base, down from 2
lvl; //scaling unchanged
}
} }
@Override @Override
public int max(int lvl) { public int max(int lvl) {
return bow != null ? 12 + 3*bow.level() : 2; if (bow != null){
} return 12 + //12 base
3*(bow.level() + lvl); //+3 per level or bow level
@Override } else {
public int STRReq(int lvl) { return 2 + //2 base, down from 5
return 9; 2*lvl; //scaling unchanged
}
} }
@Override @Override
@ -97,7 +106,7 @@ public class Dart extends MissileWeapon {
} }
@Override @Override
public int price() { public boolean isUpgradable() {
return 4 * quantity; return false;
} }
} }

View File

@ -49,13 +49,10 @@ import java.util.HashMap;
public abstract class TippedDart extends Dart { public abstract class TippedDart extends Dart {
{ {
bones = true; tier = 2;
} }
@Override //exact same damage as regular darts, despite being higher tier.
public int STRReq(int lvl) {
return 11;
}
@Override @Override
protected void rangedHit(Char enemy, int cell) { protected void rangedHit(Char enemy, int cell) {
@ -71,11 +68,6 @@ public abstract class TippedDart extends Dart {
Dungeon.level.drop( d, enemy.pos ).sprite.drop(); Dungeon.level.drop( d, enemy.pos ).sprite.drop();
} }
@Override
public int price() {
return 6 * quantity;
}
private static HashMap<Class<?extends Plant.Seed>, Class<?extends TippedDart>> types = new HashMap<>(); private static HashMap<Class<?extends Plant.Seed>, Class<?extends TippedDart>> types = new HashMap<>();
static { static {
types.put(Blindweed.Seed.class, BlindingDart.class); types.put(Blindweed.Seed.class, BlindingDart.class);

View File

@ -1313,7 +1313,7 @@ items.weapon.missiles.darts.chillingdart.desc=These darts are tipped with an ice
items.weapon.missiles.darts.dart.name=dart items.weapon.missiles.darts.dart.name=dart
items.weapon.missiles.darts.dart.desc=These simple shafts of spike-tipped wood are weighted to fly true and sting their prey with a flick of the wrist. items.weapon.missiles.darts.dart.desc=These simple shafts of spike-tipped wood are weighted to fly true and sting their prey with a flick of the wrist.
items.weapon.missiles.darts.dart.durability=Due to their size and simple construction, darts will never break from use. However specially tipped darts will lose their effect after one use. items.weapon.missiles.darts.dart.unlimited_uses=However, due to their simple construction darts will effectively last forever.
items.weapon.missiles.darts.displacingdart.name=displacing dart items.weapon.missiles.darts.displacingdart.name=displacing dart
items.weapon.missiles.darts.displacingdart.desc=These darts are tipped with a fadeleaf-based compound which will teleport their target a short distance away. items.weapon.missiles.darts.displacingdart.desc=These darts are tipped with a fadeleaf-based compound which will teleport their target a short distance away.
@ -1324,12 +1324,12 @@ items.weapon.missiles.darts.healingdart.desc=These darts are tipped with a sungr
items.weapon.missiles.darts.holydart.name=holy dart items.weapon.missiles.darts.holydart.name=holy dart
items.weapon.missiles.darts.holydart.desc=These darts are tipped with a starflower-based compound which grants a boost in power to their target. The dart itself is still harmful though. items.weapon.missiles.darts.holydart.desc=These darts are tipped with a starflower-based compound which grants a boost in power to their target. The dart itself is still harmful though.
items.weapon.missiles.darts.paralyticdart.name=paralytic dart
items.weapon.missiles.darts.paralyticdart.desc=These darts are tipped with an earthroot-based compound which will paralyze their target for a short time.
items.weapon.missiles.darts.incendiarydart.name=incendiary dart items.weapon.missiles.darts.incendiarydart.name=incendiary dart
items.weapon.missiles.darts.incendiarydart.desc=These darts are tipped with a firebloom-based compound which will burst into brilliant flames on impact. items.weapon.missiles.darts.incendiarydart.desc=These darts are tipped with a firebloom-based compound which will burst into brilliant flames on impact.
items.weapon.missiles.darts.paralyticdart.name=paralytic dart
items.weapon.missiles.darts.paralyticdart.desc=These darts are tipped with an earthroot-based compound which will paralyze their target for a short time.
items.weapon.missiles.darts.poisondart.name=poison dart items.weapon.missiles.darts.poisondart.name=poison dart
items.weapon.missiles.darts.poisondart.desc=These darts are tipped with a sorrowmoss-based compound which will poison their target. items.weapon.missiles.darts.poisondart.desc=These darts are tipped with a sorrowmoss-based compound which will poison their target.
@ -1342,6 +1342,7 @@ items.weapon.missiles.darts.shockingdart.desc=These darts are tipped with a stor
items.weapon.missiles.darts.sleepdart.name=sleep dart items.weapon.missiles.darts.sleepdart.name=sleep dart
items.weapon.missiles.darts.sleepdart.desc=These darts are tipped with a dreamfoil-based compound which will instantly put their target into a light sleep. items.weapon.missiles.darts.sleepdart.desc=These darts are tipped with a dreamfoil-based compound which will instantly put their target into a light sleep.
items.weapon.missiles.darts.tippeddart.unlimited_uses=Tipped darts will expend their effect once used and will become regular darts.
items.weapon.missiles.bolas.name=bolas items.weapon.missiles.bolas.name=bolas
@ -1360,10 +1361,11 @@ items.weapon.missiles.fishingspear.desc=Tiny throwing spears designed for fishin
items.weapon.missiles.javelin.name=javelin items.weapon.missiles.javelin.name=javelin
items.weapon.missiles.javelin.desc=These larger throwing spears are weighted to keep the spike at their tip foremost as they sail through the air. items.weapon.missiles.javelin.desc=These larger throwing spears are weighted to keep the spike at their tip foremost as they sail through the air.
items.weapon.missiles.missileweapon.stats=This missile weapon deals _%1$d-%2$d damage_ and requires _%3$d strength_ to use properly. items.weapon.missiles.missileweapon.stats=This _tier-%1$d_ missile weapon deals _%2$d-%3$d damage_ and requires _%4$d strength_ to use properly.
items.weapon.missiles.missileweapon.distance=This weapon is designed to be used at a distance, it is much less accurate at melee range. items.weapon.missiles.missileweapon.distance=This weapon is designed to be used at a distance, it is much less accurate at melee range.
items.weapon.missiles.missileweapon.durability=Missile weapons will wear out and break as they are used. items.weapon.missiles.missileweapon.durability=Missile weapons will wear out and break as they are used.
items.weapon.missiles.missileweapon.uses_left=This stack of weapons has _%d/%d_ uses left before one breaks. items.weapon.missiles.missileweapon.uses_left=This stack of weapons has _%d/%d_ uses left before one breaks.
items.weapon.missiles.missileweapon.unlimited_uses=_But these are of such high quality that they will effectively last forever._
items.weapon.missiles.shuriken.name=shuriken items.weapon.missiles.shuriken.name=shuriken
items.weapon.missiles.shuriken.desc=Star-shaped pieces of metal with razor-sharp blades. They are lightweight and easy to use on the move. A single shuriken can be thrown instantly after moving. items.weapon.missiles.shuriken.desc=Star-shaped pieces of metal with razor-sharp blades. They are lightweight and easy to use on the move. A single shuriken can be thrown instantly after moving.