v3.0.0: Hunger and Regen now both tick for partial amounts once per turn

previously they ticked for static amounts at a variable speed, defaulting to every 10 turns. The actual hunger/regen rate is unchanged, but this should make the buffs more responsive
This commit is contained in:
Evan Debenham
2025-02-06 14:30:39 -05:00
parent d4f90596a1
commit 816494c8df
3 changed files with 60 additions and 79 deletions

View File

@@ -36,8 +36,6 @@ import com.watabou.utils.Bundle;
public class Hunger extends Buff implements Hero.Doom { public class Hunger extends Buff implements Hero.Doom {
private static final float STEP = 10f;
public static final float HUNGRY = 300f; public static final float HUNGRY = 300f;
public static final float STARVING = 450f; public static final float STARVING = 450f;
@@ -68,7 +66,7 @@ public class Hunger extends Buff implements Hero.Doom {
|| target.buff(WellFed.class) != null || target.buff(WellFed.class) != null
|| SPDSettings.intro() || SPDSettings.intro()
|| target.buff(ScrollOfChallenge.ChallengeArena.class) != null){ || target.buff(ScrollOfChallenge.ChallengeArena.class) != null){
spend(STEP); spend(TICK);
return true; return true;
} }
@@ -78,7 +76,7 @@ public class Hunger extends Buff implements Hero.Doom {
if (isStarving()) { if (isStarving()) {
partialDamage += STEP * target.HT/1000f; partialDamage += target.HT/1000f;
if (partialDamage > 1){ if (partialDamage > 1){
target.damage( (int)partialDamage, this); target.damage( (int)partialDamage, this);
@@ -87,13 +85,20 @@ public class Hunger extends Buff implements Hero.Doom {
} else { } else {
float newLevel = level + STEP; float hungerDelay = 1f;
if (target.buff(Shadows.class) != null){
hungerDelay *= 1.5f;
}
hungerDelay /= SaltCube.hungerGainMultiplier();
float newLevel = level + (1f/hungerDelay);
if (newLevel >= STARVING) { if (newLevel >= STARVING) {
GLog.n( Messages.get(this, "onstarving") ); GLog.n( Messages.get(this, "onstarving") );
hero.damage( 1, this ); hero.damage( 1, this );
hero.interrupt(); hero.interrupt();
newLevel = STARVING;
} else if (newLevel >= HUNGRY && level < HUNGRY) { } else if (newLevel >= HUNGRY && level < HUNGRY) {
@@ -108,13 +113,7 @@ public class Hunger extends Buff implements Hero.Doom {
} }
float hungerDelay = STEP; spend( TICK );
if (target.buff(Shadows.class) != null){
hungerDelay *= 1.5f;
}
hungerDelay /= SaltCube.hungerGainMultiplier();
spend( hungerDelay );
} else { } else {

View File

@@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.ChaliceOfBlood;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ChaoticCenser; import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.ChaoticCenser;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.SaltCube; import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.SaltCube;
import com.watabou.utils.Bundle;
public class Regeneration extends Buff { public class Regeneration extends Buff {
@@ -37,7 +38,9 @@ public class Regeneration extends Buff {
actPriority = HERO_PRIO - 1; actPriority = HERO_PRIO - 1;
} }
private static final float REGENERATION_DELAY = 10; private float partialRegen = 0f;
private static final float REGENERATION_DELAY = 10; //1HP every 10 turns
@Override @Override
public boolean act() { public boolean act() {
@@ -49,45 +52,44 @@ public class Regeneration extends Buff {
Buff.affect(Dungeon.hero, ChaoticCenser.CenserGasTracker.class); Buff.affect(Dungeon.hero, ChaoticCenser.CenserGasTracker.class);
} }
//cancel regenning entirely in thie case if (regenOn() && target.HP < regencap() && !((Hero)target).isStarving()) {
if (SaltCube.healthRegenMultiplier() == 0){ boolean chaliceCursed = false;
spend(REGENERATION_DELAY); int chaliceLevel = -1;
return true; if (target.buff(MagicImmune.class) == null) {
} if (Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class) != null) {
chaliceCursed = Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class).isCursed();
chaliceLevel = Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class).itemLevel();
} else if (Dungeon.hero.buff(SpiritForm.SpiritFormBuff.class) != null
&& Dungeon.hero.buff(SpiritForm.SpiritFormBuff.class).artifact() instanceof ChaliceOfBlood) {
chaliceLevel = SpiritForm.artifactLevel();
}
}
if (target.HP < regencap() && !((Hero)target).isStarving()) { float delay = REGENERATION_DELAY;
if (regenOn()) { if (chaliceLevel != -1 && target.buff(MagicImmune.class) == null) {
if (chaliceCursed) {
delay *= 1.5f;
} else {
//15% boost at +0, scaling to a 500% boost at +10
delay -= 1.33f + chaliceLevel*0.667f;
delay /= RingOfEnergy.artifactChargeMultiplier(target);
}
}
delay /= SaltCube.healthRegenMultiplier();
partialRegen += 1f / delay;
if (partialRegen >= 1) {
target.HP += 1; target.HP += 1;
partialRegen--;
if (target.HP == regencap()) { if (target.HP == regencap()) {
((Hero) target).resting = false; ((Hero) target).resting = false;
} }
} }
} }
boolean chaliceCursed = false; spend( TICK );
int chaliceLevel = -1;
if (target.buff(MagicImmune.class) == null) {
if (Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class) != null) {
chaliceCursed = Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class).isCursed();
chaliceLevel = Dungeon.hero.buff(ChaliceOfBlood.chaliceRegen.class).itemLevel();
} else if (Dungeon.hero.buff(SpiritForm.SpiritFormBuff.class) != null
&& Dungeon.hero.buff(SpiritForm.SpiritFormBuff.class).artifact() instanceof ChaliceOfBlood) {
chaliceLevel = SpiritForm.artifactLevel(); //TODO this doesn't work well atm due to prior delay
}
}
float delay = REGENERATION_DELAY;
if (chaliceLevel != -1 && target.buff(MagicImmune.class) == null) {
if (chaliceCursed) {
delay *= 1.5f;
} else {
//15% boost at +0, scaling to a 500% boost at +10
delay -= 1.33f + chaliceLevel*0.667f;
delay /= RingOfEnergy.artifactChargeMultiplier(target);
}
}
delay /= SaltCube.healthRegenMultiplier();
spend( delay );
} else { } else {
@@ -98,23 +100,6 @@ public class Regeneration extends Buff {
return true; return true;
} }
//helper method for resetting the delay when salt cube buff changes, to counter exploits
public void resetDelay( SaltCube cube ){
ChaliceOfBlood.chaliceRegen regenBuff = Dungeon.hero.buff( ChaliceOfBlood.chaliceRegen.class);
float delay = REGENERATION_DELAY;
if (regenBuff != null && target.buff(MagicImmune.class) == null) {
if (regenBuff.isCursed()) {
delay *= 1.5f;
} else {
//15% boost at +0, scaling to a 500% boost at +10
delay -= 1.33f + regenBuff.itemLevel()*0.667f;
delay /= RingOfEnergy.artifactChargeMultiplier(target);
}
}
delay /= SaltCube.healthRegenMultiplier(cube.level());
postpone( delay );
}
public int regencap(){ public int regencap(){
return target.HT; return target.HT;
} }
@@ -126,4 +111,18 @@ public class Regeneration extends Buff {
} }
return true; return true;
} }
public static final String PARTIAL_REGEN = "partial_regen";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(PARTIAL_REGEN, partialRegen);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
partialRegen = bundle.getFloat(PARTIAL_REGEN);
}
} }

View File

@@ -21,10 +21,6 @@
package com.shatteredpixel.shatteredpixeldungeon.items.trinkets; package com.shatteredpixel.shatteredpixeldungeon.items.trinkets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Regeneration;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
@@ -40,19 +36,6 @@ public class SaltCube extends Trinket {
return 6+2*level(); return 6+2*level();
} }
@Override
protected void onDetach() {
//resets regen delay to counter exploits involving juggling the salt cube.
Buff.affect(Dungeon.hero, Regeneration.class).resetDelay(this);
}
@Override
public boolean doPickUp(Hero hero, int pos) {
//resets regen delay to counter exploits involving juggling the salt cube.
Buff.affect(Dungeon.hero, Regeneration.class).resetDelay(this);
return super.doPickUp(hero, pos);
}
@Override @Override
public String statsDesc() { public String statsDesc() {
if (isIdentified()){ if (isIdentified()){