diff --git a/core/src/main/assets/items.png b/core/src/main/assets/items.png
index a78acb238..339594248 100644
Binary files a/core/src/main/assets/items.png and b/core/src/main/assets/items.png differ
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/QuickSlot.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/QuickSlot.java
index c36c2399b..3446173e6 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/QuickSlot.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/QuickSlot.java
@@ -92,12 +92,15 @@ public class QuickSlot {
}
public void convertToPlaceholder(Item item){
- Item placeholder = item.virtual();
-
- if (placeholder != null && contains(item))
- for (int i = 0; i < SIZE; i++)
- if (getItem(i) == item)
- setSlot( i , placeholder );
+
+ if (contains(item)) {
+ Item placeholder = item.virtual();
+ if (placeholder == null) return;
+
+ for (int i = 0; i < SIZE; i++) {
+ if (getItem(i) == item) setSlot(i, placeholder);
+ }
+ }
}
public Item randomNonePlaceholder(){
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 b5a989aac..8233418a5 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
@@ -1248,6 +1248,8 @@ public class Hero extends Char {
sprite.showStatus( CharSprite.POSITIVE, Messages.get(Hero.class, "level_up") );
Sample.INSTANCE.play( Assets.SND_LEVELUP );
+ Item.updateQuickslot();
+
Badges.validateLevelReached();
}
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java
index 0b7bf3775..4c50dd844 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/HeroClass.java
@@ -39,11 +39,11 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfMindVision
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfMagicMissile;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Dagger;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Knuckles;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WornShortsword;
-import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Boomerang;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.ThrowingKnife;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.ThrowingStone;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@@ -168,10 +168,10 @@ public enum HeroClass {
private static void initHuntress( Hero hero ) {
(hero.belongings.weapon = new Knuckles()).identify();
- Boomerang boomerang = new Boomerang();
- boomerang.identify().collect();
+ SpiritBow bow = new SpiritBow();
+ bow.identify().collect();
- Dungeon.quickslot.setSlot(0, boomerang);
+ Dungeon.quickslot.setSlot(0, bow);
new VelvetPouch().collect();
Dungeon.LimitedDrops.VELVET_POUCH.drop();
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java
index ab0e731ea..46919ef17 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java
@@ -447,7 +447,7 @@ public class Item implements Bundlable {
return quantity != 1 ? Integer.toString( quantity ) : null;
}
- public void updateQuickslot() {
+ public static void updateQuickslot() {
QuickSlotButton.refresh();
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java
index 58dfc7097..e4deb4c2c 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/Armor.java
@@ -491,7 +491,7 @@ public class Armor extends EquipableItem {
public Armor inscribe( Glyph glyph ) {
this.glyph = glyph;
-
+ updateQuickslot();
return this;
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java
new file mode 100644
index 000000000..04ce4675b
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/SpiritBow.java
@@ -0,0 +1,221 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2018 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;
+
+import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
+import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
+import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
+import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
+import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
+import com.shatteredpixel.shatteredpixeldungeon.effects.Splash;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
+import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
+import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector;
+import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
+import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
+import com.watabou.utils.Random;
+
+import java.util.ArrayList;
+
+public class SpiritBow extends Weapon {
+
+ public static final String AC_SHOOT = "SHOOT";
+
+ {
+ image = ItemSpriteSheet.SPIRIT_BOW;
+
+ defaultAction = AC_SHOOT;
+ usesTargeting = true;
+
+ unique = true;
+ bones = false;
+ }
+
+ @Override
+ public ArrayList actions(Hero hero) {
+ ArrayList actions = super.actions(hero);
+ actions.remove(AC_EQUIP);
+ actions.add(AC_SHOOT);
+ return actions;
+ }
+
+ @Override
+ public void execute(Hero hero, String action) {
+ super.execute(hero, action);
+ if (action.equals(AC_SHOOT)) {
+ GameScene.selectCell( shooter );
+ }
+ }
+
+ @Override
+ public String info() {
+ String info = desc();
+
+ info += "\n\n" + Messages.get( SpiritBow.class, "stats",
+ Math.round(augment.damageFactor(min())),
+ Math.round(augment.damageFactor(max())),
+ STRReq());
+
+ if (STRReq() > Dungeon.hero.STR()) {
+ info += " " + Messages.get(Weapon.class, "too_heavy");
+ } else if (Dungeon.hero.heroClass == HeroClass.HUNTRESS && Dungeon.hero.STR() > STRReq()){
+ info += " " + Messages.get(Weapon.class, "excess_str", Dungeon.hero.STR() - STRReq());
+ }
+
+ switch (augment) {
+ case SPEED:
+ info += "\n\n" + Messages.get(Weapon.class, "faster");
+ break;
+ case DAMAGE:
+ info += "\n\n" + Messages.get(Weapon.class, "stronger");
+ break;
+ case NONE:
+ }
+
+ if (enchantment != null && (cursedKnown || !enchantment.curse())){
+ info += "\n\n" + Messages.get(Weapon.class, "enchanted", enchantment.name());
+ info += " " + Messages.get(enchantment, "desc");
+ }
+
+ if (cursed && isEquipped( Dungeon.hero )) {
+ info += "\n\n" + Messages.get(Weapon.class, "cursed_worn");
+ } else if (cursedKnown && cursed) {
+ info += "\n\n" + Messages.get(Weapon.class, "cursed");
+ } else if (!isIdentified() && cursedKnown){
+ info += "\n\n" + Messages.get(Weapon.class, "not_cursed");
+ }
+
+ info += "\n\n" + Messages.get(MissileWeapon.class, "distance");
+
+ return info;
+ }
+
+ @Override
+ public int STRReq(int lvl) {
+ lvl = Math.max(0, lvl);
+ //strength req decreases at +1,+3,+6,+10,etc.
+ return 10 - (int)(Math.sqrt(8 * lvl + 1) - 1)/2;
+ }
+
+ @Override
+ public int min(int lvl) {
+ return 1 + Dungeon.hero.lvl/6;
+ }
+
+ @Override
+ public int max(int lvl) {
+ return 6 + Dungeon.hero.lvl/3;
+ }
+
+ @Override
+ public int damageRoll(Char owner) {
+ int damage = augment.damageFactor(super.damageRoll( owner ));
+
+ if (owner instanceof Hero) {
+ int exStr = ((Hero)owner).STR() - STRReq();
+ if (exStr > 0) {
+ damage += Random.IntRange( 0, exStr );
+ }
+ }
+
+ return damage;
+ }
+
+ @Override
+ public int level() {
+ return Dungeon.hero.lvl/5;
+ }
+
+ @Override
+ public int visiblyUpgraded() {
+ return level();
+ }
+
+ //for fetching upgrades from a boomerang from pre-0.7.0
+ //TODO implement on this
+ public int spentUpgrades() {
+ return super.level();
+ }
+
+ @Override
+ public boolean isUpgradable() {
+ return false;
+ }
+
+ public class SpiritArrow extends MissileWeapon {
+
+ {
+ image = ItemSpriteSheet.SPIRIT_ARROW;
+ }
+
+ @Override
+ public int damageRoll(Char owner) {
+ return SpiritBow.this.damageRoll(owner);
+ }
+
+ @Override
+ public boolean hasEnchant(Class extends Enchantment> type, Char owner) {
+ return SpiritBow.this.hasEnchant(type, owner);
+ }
+
+ @Override
+ public int proc(Char attacker, Char defender, int damage) {
+ return SpiritBow.this.proc(attacker, defender, damage);
+ }
+
+ @Override
+ public float castDelay(Char user, int dst) {
+ return SpiritBow.this.speedFactor(user);
+ }
+
+ @Override
+ public int STRReq(int lvl) {
+ return SpiritBow.this.STRReq(lvl);
+ }
+
+ @Override
+ protected void onThrow( int cell ) {
+ Char enemy = Actor.findChar( cell );
+ if (enemy == null || enemy == curUser) {
+ parent = null;
+ Splash.at( cell, 0xCC99FFFF, 1 );
+ } else {
+ if (!curUser.shoot( enemy, this )) {
+ Splash.at(cell, 0xCC99FFFF, 1);
+ }
+ }
+ }
+ }
+
+ private CellSelector.Listener shooter = new CellSelector.Listener() {
+ @Override
+ public void onSelect( Integer target ) {
+ if (target != null) {
+ new SpiritArrow().cast(curUser, target);
+ }
+ }
+ @Override
+ public String prompt() {
+ return Messages.get(SpiritBow.class, "prompt");
+ }
+ };
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java
index cc963f0ae..580808afb 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java
@@ -239,6 +239,7 @@ abstract public class Weapon extends KindOfWeapon {
public Weapon enchant( Enchantment ench ) {
enchantment = ench;
+ updateQuickslot();
return this;
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/darts/Dart.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/darts/Dart.java
index 1ad9677bf..cb5be2104 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/darts/Dart.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/darts/Dart.java
@@ -24,8 +24,6 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune;
-import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
-import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Projecting;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Crossbow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
@@ -76,12 +74,11 @@ public class Dart extends MissileWeapon {
}
@Override
- public int throwPos(Hero user, int dst) {
- if (bow != null && bow.hasEnchant(Projecting.class, user)
- && !Dungeon.level.solid[dst] && Dungeon.level.distance(user.pos, dst) <= 4){
- return dst;
+ public boolean hasEnchant(Class extends Enchantment> type, Char owner) {
+ if (bow != null && bow.hasEnchant(type, owner)){
+ return true;
} else {
- return super.throwPos(user, dst);
+ return super.hasEnchant(type, owner);
}
}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java
index 8caa841fe..b07ce86b2 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java
@@ -77,14 +77,17 @@ public class ItemSpriteSheet {
public static final int DEWDROP = UNCOLLECTIBLE+1;
public static final int PETAL = UNCOLLECTIBLE+2;
public static final int SANDBAG = UNCOLLECTIBLE+3;
+ public static final int SPIRIT_ARROW = UNCOLLECTIBLE+4;
- public static final int GUIDE_PAGE = UNCOLLECTIBLE+5;
- public static final int ALCH_PAGE = UNCOLLECTIBLE+6;
+ public static final int GUIDE_PAGE = UNCOLLECTIBLE+6;
+ public static final int ALCH_PAGE = UNCOLLECTIBLE+7;
static{
assignItemRect(GOLD, 15, 13);
assignItemRect(DEWDROP, 10, 10);
assignItemRect(PETAL, 8, 8);
assignItemRect(SANDBAG, 10, 10);
+ assignItemRect(SPIRIT_ARROW,11, 11);
+
assignItemRect(GUIDE_PAGE, 10, 11);
assignItemRect(ALCH_PAGE, 10, 11);
}
@@ -256,7 +259,7 @@ public class ItemSpriteSheet {
//8 free slots
private static final int MISSILE_WEP = xy(1, 10); //16 slots. 3 per tier + boomerang
- public static final int BOOMERANG = MISSILE_WEP+0;
+ public static final int SPIRIT_BOW = MISSILE_WEP+0;
public static final int DART = MISSILE_WEP+1;
public static final int THROWING_KNIFE = MISSILE_WEP+2;
@@ -267,6 +270,7 @@ public class ItemSpriteSheet {
public static final int THROWING_SPEAR = MISSILE_WEP+7;
public static final int BOLAS = MISSILE_WEP+8;
+ public static final int BOOMERANG = MISSILE_WEP+9;
public static final int JAVELIN = MISSILE_WEP+10;
public static final int TOMAHAWK = MISSILE_WEP+11;
@@ -275,7 +279,7 @@ public class ItemSpriteSheet {
public static final int THROWING_HAMMER = MISSILE_WEP+14;
static{
- assignItemRect(BOOMERANG, 14, 14);
+ assignItemRect(SPIRIT_BOW, 16, 16);
assignItemRect(DART, 15, 15);
assignItemRect(THROWING_KNIFE, 12, 13);
@@ -286,6 +290,7 @@ public class ItemSpriteSheet {
assignItemRect(THROWING_SPEAR, 13, 13);
assignItemRect(BOLAS, 15, 14);
+ assignItemRect(BOOMERANG, 14, 14);
assignItemRect(JAVELIN, 16, 16);
assignItemRect(TOMAHAWK, 13, 13);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MissileSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MissileSprite.java
index 509d51e9d..b1752a2f4 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MissileSprite.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/MissileSprite.java
@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Crossbow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Bolas;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Boomerang;
@@ -80,6 +81,7 @@ public class MissileSprite extends ItemSprite implements Tweener.Listener {
private static final HashMap, Integer> ANGULAR_SPEEDS = new HashMap<>();
static {
+ ANGULAR_SPEEDS.put(SpiritBow.SpiritArrow.class, 0);
ANGULAR_SPEEDS.put(Dart.class, 0);
ANGULAR_SPEEDS.put(ThrowingKnife.class, 0);
ANGULAR_SPEEDS.put(FishingSpear.class, 0);
@@ -132,6 +134,9 @@ public class MissileSprite extends ItemSprite implements Tweener.Listener {
if (item instanceof Dart && Dungeon.hero.belongings.weapon instanceof Crossbow){
speed *= 3f;
}
+ if (item instanceof SpiritBow.SpiritArrow){
+ speed *= 1.5f;
+ }
PosTweener tweener = new PosTweener( this, to, d.length() / speed );
tweener.listener = this;
parent.add( tweener );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java
index 041a03499..61e971456 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java
@@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTransmutat
import com.shatteredpixel.shatteredpixeldungeon.items.spells.Recycle;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfDetectCurse;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.SpiritBow;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Boomerang;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
@@ -393,7 +394,7 @@ public class WndBag extends WndTabbed {
mode == Mode.QUICKSLOT && (item.defaultAction != null) ||
mode == Mode.WEAPON && (item instanceof MeleeWeapon || item instanceof Boomerang) ||
mode == Mode.ARMOR && (item instanceof Armor) ||
- mode == Mode.ENCHANTABLE && (item instanceof MeleeWeapon || item instanceof Boomerang || item instanceof Armor) ||
+ mode == Mode.ENCHANTABLE && (item instanceof MeleeWeapon || item instanceof SpiritBow || item instanceof Armor) ||
mode == Mode.WAND && (item instanceof Wand) ||
mode == Mode.SEED && (item instanceof Seed) ||
mode == Mode.FOOD && (item instanceof Food) ||
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStartGame.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStartGame.java
index f17b3216a..772a9d7a1 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStartGame.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndStartGame.java
@@ -333,9 +333,9 @@ public class WndStartGame extends Window {
heroMisc.icon(Icons.get(Icons.DEPTH));
break;
case HUNTRESS:
- heroItem.icon(new ItemSprite(ItemSpriteSheet.BOOMERANG, null));
+ heroItem.icon(new ItemSprite(ItemSpriteSheet.SPIRIT_BOW, null));
heroLoadout.icon(new ItemSprite(ItemSpriteSheet.KNUCKLEDUSTER, null));
- heroMisc.icon(new ItemSprite(ItemSpriteSheet.DART, null));
+ heroMisc.icon(new Image(Assets.TILES_SEWERS, 112, 96, 16, 16 ));
break;
}
diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties
index 45c9b9f27..422a6b1bd 100644
--- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties
+++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties
@@ -312,9 +312,9 @@ actors.hero.heroclass.rogue_desc_misc=The Rogue detects secrets and traps from a
actors.hero.heroclass.rogue_desc_subclasses=A subclass can be chosen after defeating the second boss. The Rogue has two subclasses:
actors.hero.heroclass.huntress=huntress
-actors.hero.heroclass.huntress_desc_item=The Huntress starts with a _unique boomerang,_ which can be thrown an infinite number of times.\n\nThe boomerang is upgradeable and can be imbued and enchanted, just like a melee weapon.
-actors.hero.heroclass.huntress_desc_loadout=The Huntress starts with _knuckledusters,_ which attack much faster than other starter weapons.\n\nThe Huntress starts with her boomerang as a ranged option.\n\nThe Huntress starts with a _velvet pouch,_ which can store small items like seeds and runestones.
-actors.hero.heroclass.huntress_desc_misc=The Huntress gains bonus damage from excess strength on thrown weapons.\n\nThe Huntress can use thrown weapons for longer before they break.\n\nThe Huntress senses nearby enemies even if they are hidden behind obstacles.\n\nThe Huntress automatically identifies potions of mind vision.
+actors.hero.heroclass.huntress_desc_item=The Huntress starts with a _unique spirit bow,_ which can fire an infinite number of conjured arrows.\n\nThe bow steadily grows stronger as the huntress levels up, and can be augmented and enchanted.
+actors.hero.heroclass.huntress_desc_loadout=The Huntress starts with _knuckledusters,_ which attack much faster than other starter weapons.\n\nThe Huntress starts with her bow as a ranged option.\n\nThe Huntress starts with a _velvet pouch,_ which can store small items like seeds and runestones.
+actors.hero.heroclass.huntress_desc_misc=The Huntress can travel through tall grass without trampling it.\n\nThe Huntress gains bonus damage from excess strength on thrown weapons.\n\nThe Huntress can use thrown weapons for longer before they break.\n\nThe Huntress senses nearby enemies even if they are hidden behind obstacles.\n\nThe Huntress automatically identifies potions of mind vision.
actors.hero.heroclass.huntress_desc_subclasses=A subclass can be chosen after defeating the second boss. The Huntress has two subclasses:
actors.hero.herosubclass.gladiator=gladiator
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 1cf009a16..644d2a80c 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
@@ -1410,6 +1410,12 @@ items.weapon.missiles.trident.name=trident
items.weapon.missiles.trident.desc=Massive throwing spears with three deadly prongs on the end. They are powerful, but quite heavy.
+items.weapon.spiritbow.name=Spirit Bow
+items.weapon.spiritbow.ac_shoot=SHOOT
+items.weapon.spiritbow.prompt=Choose a target
+items.weapon.spiritbow.stats=The bow cannot be directly upgraded, but will instead steadily grow stronger as you level up. At your current level, arrows shot from the bow will deal _%1$d-%2$d damage_ and require _%3$d strength_ to use properly.
+items.weapon.spiritbow.desc=A bow made of out ancient magical wood. The bow's string and etchings glow with a pale blue light. When the string is pulled this bow will conjure a magical arrow which can be fired at an enemy.
+
items.weapon.weapon.identify=You are now familiar enough with your weapon to identify it.
items.weapon.weapon.too_heavy=Because of your inadequate strength this weapon will hinder your attack speed, accuracy, and ability to surprise attack.
items.weapon.weapon.excess_str=Because of your excess strength, you will deal up to _%d bonus damage_ with this weapon.