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 6300d7a83..5f5fbc215 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 @@ -295,9 +295,6 @@ public class Hero extends Char { public int tier() { return belongings.armor == null ? 0 : belongings.armor.tier; } - - //this variable is only needed because of the boomerang, remove if/when it is no longer equippable - boolean rangedAttack = false; public boolean shoot( Char enemy, MissileWeapon wep ) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java index 3b3becdd0..9b9e5a570 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java @@ -138,8 +138,10 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sword; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WarHammer; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Whip; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WornShortsword; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.HeavyBoomerang; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Bolas; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.FishingSpear; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.ForceCube; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Javelin; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Kunai; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon; @@ -398,15 +400,17 @@ public class Generator { MIS_T4.classes = new Class[]{ Javelin.class, - Tomahawk.class + Tomahawk.class, + HeavyBoomerang.class }; - MIS_T4.probs = new float[]{ 4, 3 }; + MIS_T4.probs = new float[]{ 6, 5, 4 }; MIS_T5.classes = new Class[]{ Trident.class, - ThrowingHammer.class + ThrowingHammer.class, + ForceCube.class }; - MIS_T5.probs = new float[]{ 4, 3 }; + MIS_T5.probs = new float[]{ 6, 5, 4 }; FOOD.classes = new Class[]{ Food.class, diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ForceCube.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ForceCube.java new file mode 100644 index 000000000..c992497b6 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ForceCube.java @@ -0,0 +1,67 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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 + */ + +package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles; + +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.items.wands.WandOfBlastWave; +import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.PathFinder; + +import java.util.ArrayList; + +public class ForceCube extends MissileWeapon { + + { + image = ItemSpriteSheet.FORCE_CUBE; + + tier = 5; + baseUses = 5; + + sticky = false; + } + + @Override + protected void onThrow(int cell) { + Dungeon.level.press(cell, null, true); + + ArrayList targets = new ArrayList<>(); + if (Actor.findChar(cell) != null) targets.add(Actor.findChar(cell)); + + for (int i : PathFinder.NEIGHBOURS8){ + Dungeon.level.press(cell + i, null, true); + if (Actor.findChar(cell + i) != null) targets.add(Actor.findChar(cell + i)); + } + + for (Char target : targets){ + curUser.shoot(target, this); + } + + rangedHit( null, cell ); + + WandOfBlastWave.BlastWave.blast(cell); + Sample.INSTANCE.play( Assets.SND_BLAST ); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java new file mode 100644 index 000000000..23ba3dbe8 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java @@ -0,0 +1,143 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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 + */ + +package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles; + +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.sprites.ItemSpriteSheet; +import com.shatteredpixel.shatteredpixeldungeon.sprites.MissileSprite; +import com.watabou.utils.Bundle; +import com.watabou.utils.Callback; + +public class HeavyBoomerang extends MissileWeapon { + + { + image = ItemSpriteSheet.BOOMERANG; + + tier = 4; + sticky = false; + } + + @Override + public int max(int lvl) { + return 4 * tier + //16 base, down from 20 + (tier) * lvl; //scaling unchanged + } + + @Override + protected void rangedHit(Char enemy, int cell) { + decrementDurability(); + if (durability > 0){ + //TODO vfx + Buff.append(Dungeon.hero, CircleBack.class).setup(this, cell, Dungeon.hero.pos, Dungeon.depth); + } + } + + @Override + protected void rangedMiss(int cell) { + //TODO vfx + parent = null; + Buff.append(Dungeon.hero, CircleBack.class).setup(this, cell, Dungeon.hero.pos, Dungeon.depth); + } + + public static class CircleBack extends Buff { + + private MissileWeapon boomerang; + private int thrownPos; + private int returnPos; + private int returnDepth; + + private int left; + + public void setup( MissileWeapon boomerang, int thrownPos, int returnPos, int returnDepth){ + this.boomerang = boomerang; + this.thrownPos = thrownPos; + this.returnPos = returnPos; + this.returnDepth = returnDepth; + left = 3; + } + + @Override + public boolean act() { + if (returnDepth == Dungeon.depth){ + left--; + if (left <= 0){ + final Char returnTarget = Actor.findChar(returnPos); + ((MissileSprite) Dungeon.hero.sprite.parent.recycle(MissileSprite.class)). + reset( thrownPos, + returnPos, + boomerang, + new Callback() { + @Override + public void call() { + if (returnTarget == Dungeon.hero){ + boomerang.doPickUp(Dungeon.hero); + //grabbing the boomerang takes no time + Dungeon.hero.spend( -TIME_TO_PICK_UP ); + + } else if (returnTarget != null){ + if (curUser.shoot( returnTarget, boomerang )) { + boomerang.decrementDurability(); + } + if (boomerang.durability > 0) { + Dungeon.level.drop(boomerang, returnPos).sprite.drop(); + } + + } else { + Dungeon.level.drop(boomerang, returnPos).sprite.drop(); + } + } + }); + detach(); + } + } + spend( TICK ); + return true; + } + + private static final String BOOMERANG = "boomerang"; + private static final String THROWN_POS = "thrown_pos"; + private static final String RETURN_POS = "return_pos"; + private static final String RETURN_DEPTH = "return_depth"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(BOOMERANG, boomerang); + bundle.put(THROWN_POS, thrownPos); + bundle.put(RETURN_POS, returnPos); + bundle.put(RETURN_DEPTH, returnDepth); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + boomerang = (MissileWeapon) bundle.get(BOOMERANG); + thrownPos = bundle.getInt(THROWN_POS); + returnPos = bundle.getInt(RETURN_POS); + returnDepth = bundle.getInt(RETURN_DEPTH); + } + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java index 9b2de9709..346f22d64 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java @@ -198,37 +198,17 @@ abstract public class MissileWeapon extends Weapon { } protected void rangedHit( Char enemy, int cell ){ - //if this weapon was thrown from a source stack, degrade that stack. - //unless a weapon is about to break, then break the one being thrown - if (parent != null){ - if (parent.durability <= parent.durabilityPerUse()){ - durability = 0; - parent.durability = MAX_DURABILITY; - } else { - parent.durability -= parent.durabilityPerUse(); - if (parent.durability > 0 && parent.durability <= parent.durabilityPerUse()){ - if (level() <= 0)GLog.w(Messages.get(this, "about_to_break")); - else GLog.n(Messages.get(this, "about_to_break")); - } - } - parent = null; - } else { - durability -= durabilityPerUse(); - if (durability > 0 && durability <= durabilityPerUse()){ - if (level() <= 0)GLog.w(Messages.get(this, "about_to_break")); - else GLog.n(Messages.get(this, "about_to_break")); - } - } + decrementDurability(); if (durability > 0){ //attempt to stick the missile weapon to the enemy, just drop it if we can't. - if (enemy.isAlive() && sticky) { + if (enemy != null && enemy.isAlive() && sticky) { PinCushion p = Buff.affect(enemy, PinCushion.class); if (p.target == enemy){ p.stick(this); return; } } - Dungeon.level.drop( this, enemy.pos ).sprite.drop(); + Dungeon.level.drop( this, cell ).sprite.drop(); } } @@ -252,6 +232,30 @@ abstract public class MissileWeapon extends Weapon { return (MAX_DURABILITY/usages) + 0.001f; } + protected void decrementDurability(){ + //if this weapon was thrown from a source stack, degrade that stack. + //unless a weapon is about to break, then break the one being thrown + if (parent != null){ + if (parent.durability <= parent.durabilityPerUse()){ + durability = 0; + parent.durability = MAX_DURABILITY; + } else { + parent.durability -= parent.durabilityPerUse(); + if (parent.durability > 0 && parent.durability <= parent.durabilityPerUse()){ + if (level() <= 0)GLog.w(Messages.get(this, "about_to_break")); + else GLog.n(Messages.get(this, "about_to_break")); + } + } + parent = null; + } else { + durability -= durabilityPerUse(); + if (durability > 0 && durability <= durabilityPerUse()){ + if (level() <= 0)GLog.w(Messages.get(this, "about_to_break")); + else GLog.n(Messages.get(this, "about_to_break")); + } + } + } + @Override public int damageRoll(Char owner) { int damage = augment.damageFactor(super.damageRoll( owner )); diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties index 8b0ba013e..d5369cb4f 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/items/items.properties @@ -1406,6 +1406,12 @@ items.weapon.missiles.boomerang.durability=Due to its solid construction, this b items.weapon.missiles.fishingspear.name=fishing spear items.weapon.missiles.fishingspear.desc=Tiny throwing spears designed for fishing. They work well as an improvised weapon too. +items.weapon.missiles.forcecube.name=force cube +items.weapon.missiles.forcecube.desc=This oddly-shaped weapon is small enough to hold in your hand, but is incredibly heavy. When thrown, it will spread the force of its impact over a small area, damaging everything in the blast. + +items.weapon.missiles.heavyboomerang.name=heavy boomerang +items.weapon.missiles.heavyboomerang.desc=This large boomerang is difficult to wield effectively, but will deal considerable damage. After a few turns, it will fly back to the location it was thrown from. + 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.