From 4e73f82c463ec0e4bcb3b5d09023d35169ae6a42 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 31 Dec 2025 15:10:31 -0500 Subject: [PATCH] v3.3.2: improved code for managing usage of targeted spells Most notably this fixes exploits on reclaim trap where it would count as used when not being consumed. --- .../items/spells/PhaseShift.java | 1 + .../items/spells/ReclaimTrap.java | 9 ++++++++- .../items/spells/TargetedSpell.java | 20 +++++++++++-------- .../items/spells/TelekineticGrab.java | 2 ++ .../items/spells/WildEnergy.java | 2 ++ 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/PhaseShift.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/PhaseShift.java index 89fa6d026..58f794a75 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/PhaseShift.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/PhaseShift.java @@ -63,6 +63,7 @@ public class PhaseShift extends TargetedSpell { } else { GLog.w( Messages.get(this, "no_target") ); } + onSpellused(); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/ReclaimTrap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/ReclaimTrap.java index 10e84c464..fcfde0e1c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/ReclaimTrap.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/ReclaimTrap.java @@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.spells; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.quest.MetalShard; @@ -82,7 +83,6 @@ public class ReclaimTrap extends TargetedSpell { } } if (storedTrap == null) { - quantity++; //storing a trap doesn't consume the spell Trap t = Dungeon.level.traps.get(bolt.collisionPos); if (t != null && t.active && t.visible) { t.disarm(); //even disarms traps that normally wouldn't be @@ -95,6 +95,11 @@ public class ReclaimTrap extends TargetedSpell { } else { GLog.w(Messages.get(this, "no_trap")); } + + //spell is not consumed, so doesn't count as a full use + Invisibility.dispel(); + curUser.spendAndNext( timeToCast() ); + } else { Trap t = Reflection.newInstance(storedTrap); @@ -103,6 +108,8 @@ public class ReclaimTrap extends TargetedSpell { t.reclaimed = true; Bestiary.countEncounter(t.getClass()); t.activate(); + + onSpellused(); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TargetedSpell.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TargetedSpell.java index 7af3c8bec..2353cefdf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TargetedSpell.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TargetedSpell.java @@ -57,6 +57,17 @@ public abstract class TargetedSpell extends Spell { Sample.INSTANCE.play( Assets.Sounds.ZAP ); } + protected void onSpellused(){ + detach( curUser.belongings.backpack ); + Invisibility.dispel(); + updateQuickslot(); + curUser.spendAndNext( timeToCast() ); + Catalog.countUse(getClass()); + if (Random.Float() < talentChance){ + Talent.onScrollUsed(curUser, curUser.pos, talentFactor, getClass()); + } + } + protected float timeToCast(){ return Actor.TICK; } @@ -93,14 +104,7 @@ public abstract class TargetedSpell extends Spell { curSpell.fx(shot, new Callback() { public void call() { curSpell.affectTarget(shot, curUser); - curSpell.detach( curUser.belongings.backpack ); - Invisibility.dispel(); - curSpell.updateQuickslot(); - curUser.spendAndNext( curSpell.timeToCast() ); - Catalog.countUse(curSpell.getClass()); - if (Random.Float() < curSpell.talentChance){ - Talent.onScrollUsed(curUser, curUser.pos, curSpell.talentFactor, curSpell.getClass()); - } + curSpell.onSpellused(); } }); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java index 2048d60ee..53ee44e74 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java @@ -59,6 +59,7 @@ public class TelekineticGrab extends TargetedSpell { @Override protected float timeToCast() { + //time is processed in the spell's logic, as it relates to items picked up return 0; } @@ -133,6 +134,7 @@ public class TelekineticGrab extends TargetedSpell { hero.spend(Actor.TICK); } + onSpellused(); } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/WildEnergy.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/WildEnergy.java index d6a3f7fab..921c62045 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/WildEnergy.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/WildEnergy.java @@ -67,6 +67,8 @@ public class WildEnergy extends TargetedSpell { Buff.affect(hero, Recharging.class, 8f); Buff.affect(hero, ArtifactRecharge.class).extend( 8 ).ignoreHornOfPlenty = false; + + onSpellused(); } @Override