diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties
index 6b4d9e030..175c42989 100644
--- a/core/src/main/assets/messages/items/items.properties
+++ b/core/src/main/assets/messages/items/items.properties
@@ -1685,6 +1685,12 @@ items.weapon.melee.scimitar.desc=A thick curved blade. Its shape allows for fast
items.weapon.melee.scimitar$sworddance.name=sword dance
items.weapon.melee.scimitar$sworddance.desc=The Duelist is making quick momentum based strikes in a sort of dance. While this stance is active, she attacks 60%% faster (enough to attack exactly twice a turn with a scimitar), but suffers -20%% accuracy.\n\nTurns remaining: %s.
+items.weapon.melee.sickle.name=sickle
+items.weapon.melee.sickle.stats_desc=This is a rather inaccurate weapon.
+items.weapon.melee.sickle.ability_name=harvest
+items.weapon.melee.sickle.ability_desc=The Duelist can _harvest_ an enemy with a sickle. This devastating attack inflicts bleed equal to 100% of damage and is guaranteed to hit, but costs 2 charges.
+items.weapon.melee.sickle.desc=A handheld farming tool that can double as a strong but unwieldy weapon.
+
items.weapon.melee.spear.name=spear
items.weapon.melee.spear.stats_desc=This is a rather slow weapon.\nThis weapon has extra reach.
items.weapon.melee.spear.ability_name=spike
@@ -1704,6 +1710,12 @@ items.weapon.melee.warhammer.ability_name=heavy blow
items.weapon.melee.warhammer.ability_desc=The Duelist can perform a _heavy blow_ with a war hammer. This strong but predictable attack has -75% accuracy, but deals +50% damage and applies vulnerable and weaken for 5 turns if it hits. Heavy blow can surprise attack.
items.weapon.melee.warhammer.desc=Few creatures can withstand the crushing blow of this towering mass of lead and steel, but it takes great strength to use effectively.
+items.weapon.melee.warscythe.name=war scythe
+items.weapon.melee.warscythe.stats_desc=This is a rather inaccurate weapon.
+items.weapon.melee.warscythe.ability_name=harvest
+items.weapon.melee.warscythe.ability_desc=The Duelist can _harvest_ an enemy with a war scythe. This devastating attack inflicts bleed equal to 80% of damage and is guaranteed to hit, but costs 2 charges.
+items.weapon.melee.warscythe.desc=This large and unwieldy tool has been reinforced to make it better at cutting foes than crops.
+
items.weapon.melee.whip.name=whip
items.weapon.melee.whip.stats_desc=This weapon has tremendous reach.
items.weapon.melee.whip.ability_name=lash
diff --git a/core/src/main/assets/sprites/items.png b/core/src/main/assets/sprites/items.png
index 0c46d64da..c34b39568 100644
Binary files a/core/src/main/assets/sprites/items.png and b/core/src/main/assets/sprites/items.png differ
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
index 7572d7d43..b43f9c560 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java
@@ -99,6 +99,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Blazin
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Kinetic;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Shocking;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sickle;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.ShockingDart;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
@@ -693,6 +694,19 @@ public abstract class Char extends Actor {
dmg -= Random.NormalIntRange(0, buff(ArcaneArmor.class).level());
if (dmg < 0) dmg = 0;
}
+
+ if (buff(Sickle.HarvestBleedTracker.class) != null){
+ Bleeding b = buff(Bleeding.class);
+ if (b == null){
+ b = new Bleeding();
+ }
+ b.announced = false;
+ b.set(dmg*buff(Sickle.HarvestBleedTracker.class).bleedFactor, Sickle.HarvestBleedTracker.class);
+ b.attachTo(this);
+ sprite.showStatus(CharSprite.WARNING, Messages.titleCase(b.name()) + " " + (int)b.level());
+ buff(Sickle.HarvestBleedTracker.class).detach();
+ return;
+ }
if (buff( Paralysis.class ) != null) {
buff( Paralysis.class ).processDamage(dmg);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bleeding.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bleeding.java
index 11b0c72c7..751224e1e 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bleeding.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Bleeding.java
@@ -25,6 +25,8 @@ import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.effects.Splash;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.curses.Sacrificial;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sickle;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
@@ -112,6 +114,10 @@ public class Bleeding extends Buff {
Dungeon.fail( getClass() );
GLog.n( Messages.get(this, "ondeath") );
}
+
+ if (source == Sickle.HarvestBleedTracker.class && !target.isAlive()){
+ MeleeWeapon.onAbilityKill(Dungeon.hero);
+ }
spend( TICK );
} else {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java
index 33e43b92c..30e48878a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/YogFist.java
@@ -44,6 +44,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sickle;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
@@ -372,7 +373,9 @@ public abstract class YogFist extends Mob {
@Override
public void damage(int dmg, Object src) {
- if (!isInvulnerable(src.getClass()) && !(src instanceof Bleeding)){
+ if (!isInvulnerable(src.getClass())
+ && !(src instanceof Bleeding)
+ && buff(Sickle.HarvestBleedTracker.class) == null){
dmg = Math.round( dmg * resist( src.getClass() ));
if (dmg < 0){
return;
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 27aa5fa7b..c19a71f28 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Generator.java
@@ -141,9 +141,11 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.RunicBlade;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sai;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Scimitar;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Shortsword;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sickle;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Spear;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Sword;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WarHammer;
+import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WarScythe;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Whip;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.WornShortsword;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.Bolas;
@@ -358,9 +360,10 @@ public class Generator {
HandAxe.class,
Spear.class,
Quarterstaff.class,
- Dirk.class
+ Dirk.class,
+ Sickle.class
};
- WEP_T2.probs = new float[]{ 6, 5, 5, 4, 4 };
+ WEP_T2.probs = new float[]{ 6, 5, 5, 4, 4, 4 };
WEP_T3.classes = new Class>[]{
Sword.class,
@@ -389,9 +392,10 @@ public class Generator {
Glaive.class,
Greataxe.class,
Greatshield.class,
- Gauntlet.class
+ Gauntlet.class,
+ WarScythe.class
};
- WEP_T5.probs = new float[]{ 6, 5, 5, 4, 4, 4 };
+ WEP_T5.probs = new float[]{ 6, 5, 5, 4, 4, 4, 4 };
//see Generator.randomArmor
ARMOR.classes = new Class>[]{
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java
index 834f01b57..ba18faf07 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java
@@ -253,7 +253,7 @@ public class MeleeWeapon extends Weapon {
}
}
- public void onAbilityKill( Hero hero ){
+ public static void onAbilityKill( Hero hero ){
if (hero.hasTalent(Talent.LETHAL_HASTE)){
//effectively 2/3 turns of haste
Buff.prolong(hero, Haste.class, 1.67f+hero.pointsInTalent(Talent.LETHAL_HASTE));
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sickle.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sickle.java
new file mode 100644
index 000000000..7e99762d6
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Sickle.java
@@ -0,0 +1,117 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2023 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.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.buffs.Invisibility;
+import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
+import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
+import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
+import com.shatteredpixel.shatteredpixeldungeon.ui.AttackIndicator;
+import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
+import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Callback;
+
+public class Sickle extends MeleeWeapon {
+
+ {
+ image = ItemSpriteSheet.SICKLE;
+ hitSound = Assets.Sounds.HIT_SLASH;
+ hitSoundPitch = 1f;
+
+ tier = 2;
+ ACC = 0.68f; //32% penalty to accuracy
+ }
+
+ @Override
+ public int max(int lvl) {
+ return Math.round(6.67f*(tier+1)) + //20 base, up from 15
+ lvl*(tier+1); //scaling unchanged
+ }
+
+ @Override
+ public String targetingPrompt() {
+ return Messages.get(this, "prompt");
+ }
+
+ @Override
+ protected void duelistAbility(Hero hero, Integer target) {
+ harvestAbility(hero, target, 1f, this);
+ }
+
+ public static void harvestAbility(Hero hero, Integer target, float bleedFactor, 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;
+ }
+
+ hero.belongings.abilityWeapon = wep;
+ if (!hero.canAttack(enemy)){
+ GLog.w(Messages.get(wep, "ability_bad_position"));
+ hero.belongings.abilityWeapon = null;
+ return;
+ }
+ hero.belongings.abilityWeapon = null;
+
+ hero.sprite.attack(enemy.pos, new Callback() {
+ @Override
+ public void call() {
+ wep.beforeAbilityUsed(hero);
+ AttackIndicator.target(enemy);
+
+ Buff.affect(enemy, HarvestBleedTracker.class, 0).bleedFactor = bleedFactor;
+ if (hero.attack(enemy, 1, 0, Char.INFINITE_ACCURACY)){
+ Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG);
+ }
+
+ Invisibility.dispel();
+ hero.spendAndNext(hero.attackDelay());
+ if (!enemy.isAlive()){
+ wep.onAbilityKill(hero);
+ Buff.prolong(hero, Sword.CleaveTracker.class, 5f);
+ } else {
+ if (hero.buff(Sword.CleaveTracker.class) != null) {
+ hero.buff(Sword.CleaveTracker.class).detach();
+ }
+ }
+ wep.afterAbilityUsed(hero);
+ }
+ });
+
+ }
+
+ public static class HarvestBleedTracker extends FlavourBuff{
+ public float bleedFactor;
+ };
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/WarScythe.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/WarScythe.java
new file mode 100644
index 000000000..fd363c147
--- /dev/null
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/WarScythe.java
@@ -0,0 +1,56 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2023 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.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 WarScythe extends MeleeWeapon {
+
+ {
+ image = ItemSpriteSheet.WAR_SCYTHE;
+ hitSound = Assets.Sounds.HIT_SLASH;
+ hitSoundPitch = 0.9f;
+
+ tier = 5;
+ ACC = 0.8f; //20% penalty to accuracy
+ }
+
+ @Override
+ public int max(int lvl) {
+ return Math.round(6.67f*(tier+1)) + //40 base, up from 30
+ lvl*(tier+1); //scaling unchanged
+ }
+
+ @Override
+ public String targetingPrompt() {
+ return Messages.get(this, "prompt");
+ }
+
+ @Override
+ protected void duelistAbility(Hero hero, Integer target) {
+ Sickle.harvestAbility(hero, target, 0.8f, this);
+ }
+
+}
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 44b22b2b0..e6d2a6687 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/ItemSpriteSheet.java
@@ -214,12 +214,14 @@ public class ItemSpriteSheet {
public static final int SPEAR = WEP_TIER2+2;
public static final int QUARTERSTAFF = WEP_TIER2+3;
public static final int DIRK = WEP_TIER2+4;
+ public static final int SICKLE = WEP_TIER2+5;
static{
assignItemRect(SHORTSWORD, 13, 13);
assignItemRect(HAND_AXE, 12, 14);
assignItemRect(SPEAR, 16, 16);
assignItemRect(QUARTERSTAFF, 16, 16);
assignItemRect(DIRK, 13, 14);
+ assignItemRect(SICKLE, 15, 15);
}
private static final int WEP_TIER3 = xy(1, 8); //8 slots
@@ -263,6 +265,7 @@ public class ItemSpriteSheet {
public static final int GREATAXE = WEP_TIER5+3;
public static final int GREATSHIELD = WEP_TIER5+4;
public static final int GAUNTLETS = WEP_TIER5+5;
+ public static final int WAR_SCYTHE = WEP_TIER5+6;
static{
assignItemRect(GREATSWORD, 16, 16);
assignItemRect(WAR_HAMMER, 16, 16);
@@ -270,6 +273,7 @@ public class ItemSpriteSheet {
assignItemRect(GREATAXE, 12, 16);
assignItemRect(GREATSHIELD, 12, 16);
assignItemRect(GAUNTLETS, 13, 15);
+ assignItemRect(WAR_SCYTHE, 14, 15);
}
//8 free slots