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.