diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java index d480f98b6..8851c0481 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java @@ -131,7 +131,7 @@ public class GamesInProgress { info.exp = hero.exp; info.hp = hero.HP; info.ht = hero.HT; - info.shld = hero.SHLD; + info.shld = hero.shielding(); info.heroClass = hero.heroClass; info.subClass = hero.subClass; info.armorTier = hero.tier(); 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 e8a465e27..9b12ff1ea 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Electricity; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Adrenaline; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bless; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; @@ -47,12 +48,15 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Preparation; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ShieldBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Slow; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Speed; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Stamina; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; +import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; +import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Brimstone; import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Potential; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfElements; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast; @@ -90,7 +94,6 @@ public abstract class Char extends Actor { public int HT; public int HP; - public int SHLD; protected float baseSpeed = 1; protected PathFinder.Path path; @@ -137,7 +140,6 @@ public abstract class Char extends Actor { bundle.put( POS, pos ); bundle.put( TAG_HP, HP ); bundle.put( TAG_HT, HT ); - bundle.put( TAG_SHLD, SHLD ); bundle.put( BUFFS, buffs ); } @@ -149,13 +151,27 @@ public abstract class Char extends Actor { pos = bundle.getInt( POS ); HP = bundle.getInt( TAG_HP ); HT = bundle.getInt( TAG_HT ); - SHLD = bundle.getInt( TAG_SHLD ); for (Bundlable b : bundle.getCollection( BUFFS )) { if (b != null) { ((Buff)b).attachTo( this ); } } + + //pre-0.7.0 + if (bundle.contains( "SHLD" )){ + int legacySHLD = bundle.getInt( "SHLD" ); + //attempt to find the buff that may have given the shield + ShieldBuff buff = buff(Brimstone.BrimstoneShield.class); + if (buff != null) legacySHLD -= buff.shielding(); + //pre beta-2.0, remove for full release + buff = buff(Barrier.class); + if (buff != null) legacySHLD -= buff.shielding(); + if (legacySHLD > 0){ + BrokenSeal.WarriorShield buff2 = buff(BrokenSeal.WarriorShield.class); + if (buff != null) buff2.supercharge(legacySHLD); + } + } } public boolean attack( Char enemy ) { @@ -288,6 +304,23 @@ public abstract class Char extends Actor { return speed; } + //used so that buffs(Shieldbuff.class) isn't called every time unnecessarily + private int cachedShield = 0; + public boolean needsShieldUpdate = true; + + public int shielding(){ + if (!needsShieldUpdate){ + return cachedShield; + } + + cachedShield = 0; + for (ShieldBuff s : buffs(ShieldBuff.class)){ + cachedShield += s.shielding(); + } + needsShieldUpdate = false; + return cachedShield; + } + public void damage( int dmg, Object src ) { if (!isAlive() || dmg < 0) { @@ -314,20 +347,21 @@ public abstract class Char extends Actor { buff( Paralysis.class ).processDamage(dmg); } + int shielded = dmg; //FIXME: when I add proper damage properties, should add an IGNORES_SHIELDS property to use here. - if (src instanceof Hunger || SHLD == 0){ - HP -= dmg; - } else if (SHLD >= dmg){ - SHLD -= dmg; - } else if (SHLD > 0) { - HP -= (dmg - SHLD); - SHLD = 0; + if (!(src instanceof Hunger)){ + for (ShieldBuff s : buffs(ShieldBuff.class)){ + dmg = s.absorbDamage(dmg); + if (dmg == 0) break; + } } + shielded -= dmg; + HP -= dmg; sprite.showStatus( HP > HT / 2 ? CharSprite.WARNING : CharSprite.NEGATIVE, - Integer.toString( dmg ) ); + Integer.toString( dmg + shielded ) ); if (HP < 0) HP = 0; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java index 2cad768d8..89a801a89 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java @@ -24,27 +24,16 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.watabou.utils.Bundle; -//FIXME managing shield buffs is starting to get cumbersome, should come up with a way to have them interact easily -public class Barrier extends Buff { - - private int level = 1; +public class Barrier extends ShieldBuff { //TODO icon and description for phase 2 @Override public boolean act() { - if (target.SHLD == level){ - target.SHLD -= 1; - } + absorbDamage(1); - level -= 1; - - if (target.SHLD <= level) { - target.SHLD = level; - } - - if (level <= 0){ + if (shielding <= 0){ detach(); } @@ -53,12 +42,9 @@ public class Barrier extends Buff { return true; } - public void set( int shielding ){ - if (level < shielding){ - level = shielding; - if (target.SHLD < level){ - target.SHLD = level; - } + public void set( int s ){ + if (shielding < s){ + shielding = s; } } @@ -68,17 +54,12 @@ public class Barrier extends Buff { else target.sprite.remove(CharSprite.State.SHIELDED); } - private static final String LEVEL = "level"; - - @Override - public void storeInBundle( Bundle bundle ) { - super.storeInBundle( bundle ); - bundle.put( LEVEL, level); - } - @Override public void restoreFromBundle( Bundle bundle ) { super.restoreFromBundle( bundle ); - level = bundle.getInt( LEVEL ); + if (bundle.contains("level")) { + //TODO pre beta-2.0, remove in full release + shielding = bundle.getInt("level"); + } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Berserk.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Berserk.java index c30593141..37484e5d6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Berserk.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Berserk.java @@ -76,10 +76,10 @@ public class Berserk extends Buff { @Override public boolean act() { if (berserking()){ + WarriorShield buff = target.buff(WarriorShield.class); if (target.HP <= 0) { - target.SHLD -= 1 + Math.ceil(target.SHLD * 0.1f); - if (target.SHLD <= 0) { - target.SHLD = 0; + buff.absorbDamage(1 + (int)Math.ceil(target.shielding() * 0.1f)); + if (target.shielding() <= 0) { target.die(this); if (!target.isAlive()) Dungeon.fail(this.getClass()); } @@ -87,7 +87,7 @@ public class Berserk extends Buff { state = State.RECOVERING; levelRecovery = LEVEL_RECOVER_START; BuffIndicator.refreshHero(); - target.SHLD = 0; + buff.absorbDamage(buff.shielding()); power = 0f; } } else if (state == State.NORMAL) { @@ -114,7 +114,7 @@ public class Berserk extends Buff { if (shield != null){ state = State.BERSERK; BuffIndicator.refreshHero(); - target.SHLD = shield.maxShield() * 10; + shield.supercharge(shield.maxShield() * 10); SpellSprite.show(target, SpellSprite.BERSERK); Sample.INSTANCE.play( Assets.SND_CHALLENGE ); @@ -123,7 +123,7 @@ public class Berserk extends Buff { } - return state == State.BERSERK && target.SHLD > 0; + return state == State.BERSERK && target.shielding() > 0; } public void damage(int damage){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Combo.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Combo.java index aa677c242..b0a27fae5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Combo.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Combo.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; @@ -266,7 +267,10 @@ public class Combo extends Buff implements ActionIndicator.Action { } break; case SLAM: - target.SHLD = Math.max( target.SHLD, dmg/2); + BrokenSeal.WarriorShield shield = Buff.affect(target, BrokenSeal.WarriorShield.class); + if (shield != null) { + shield.supercharge(dmg / 2); + } break; default: //nothing diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/ShieldBuff.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/ShieldBuff.java new file mode 100644 index 000000000..5df55ede5 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/ShieldBuff.java @@ -0,0 +1,81 @@ +/* + * 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.actors.buffs; + +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.watabou.utils.Bundle; + +public abstract class ShieldBuff extends Buff { + + protected int shielding; + + @Override + public boolean attachTo(Char target) { + if (super.attachTo(target)) { + target.needsShieldUpdate = true; + return true; + } else { + return false; + } + } + + @Override + public void detach() { + target.needsShieldUpdate = true; + super.detach(); + } + + public int shielding(){ + return shielding; + } + + //returns the amount of damage leftover + public int absorbDamage( int dmg ){ + if (shielding >= dmg){ + shielding -= dmg; + dmg = 0; + } else { + dmg -= shielding; + shielding = 0; + } + if (shielding == 0){ + detach(); + } + target.needsShieldUpdate = true; + return dmg; + } + + private static final String SHIELDING = "shielding"; + + @Override + public void storeInBundle( Bundle bundle ) { + super.storeInBundle( bundle ); + bundle.put( SHIELDING, shielding); + } + + @Override + public void restoreFromBundle( Bundle bundle ) { + super.restoreFromBundle( bundle ); + shielding = bundle.getInt( SHIELDING ); + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/BrokenSeal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/BrokenSeal.java index 8737695b2..d76b5ffb3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/BrokenSeal.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/BrokenSeal.java @@ -23,7 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ShieldBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; @@ -99,33 +99,48 @@ public class BrokenSeal extends Item { } }; - public static class WarriorShield extends Buff { + public static class WarriorShield extends ShieldBuff { private Armor armor; private float partialShield; @Override public synchronized boolean act() { - if (armor == null) detach(); - else if (armor.isEquipped((Hero)target)) { - if (target.SHLD < maxShield()){ - partialShield += 1/(35*Math.pow(0.885f, (maxShield() - target.SHLD - 1))); - } + if (shielding < maxShield()) { + partialShield += 1/(35*Math.pow(0.885f, (maxShield() - shielding - 1))); } + while (partialShield >= 1){ - target.SHLD++; + shielding++; partialShield--; + target.needsShieldUpdate = true; } + + if (shielding <= 0 && maxShield() <= 0){ + detach(); + } + spend(TICK); return true; } + + public synchronized void supercharge(int maxShield){ + if (maxShield > shielding){ + shielding = maxShield; + } + } public synchronized void setArmor(Armor arm){ armor = arm; } public synchronized int maxShield() { - return 1 + armor.tier + armor.level(); + if (armor != null && armor.isEquipped((Hero)target)) { + return 1 + armor.tier + armor.level(); + } else { + return 0; + } } + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Brimstone.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Brimstone.java index f857d6e8e..b2b888c7f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Brimstone.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Brimstone.java @@ -22,8 +22,8 @@ package com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ShieldBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite; @@ -44,23 +44,13 @@ public class Brimstone extends Armor.Glyph { return ORANGE; } - public static class BrimstoneShield extends Buff { - - private int shieldAdded; - private int lastShield = -1; + public static class BrimstoneShield extends ShieldBuff { @Override public boolean act() { Hero hero = (Hero)target; - //make sure any shielding lost through combat is accounted for - if (lastShield != -1 && lastShield > hero.SHLD) - shieldAdded = Math.max(0, shieldAdded - (lastShield - hero.SHLD)); - - lastShield = hero.SHLD; - if (hero.belongings.armor == null || !hero.belongings.armor.hasGlyph(Brimstone.class)) { - hero.SHLD -= shieldAdded; detach(); return true; } @@ -69,10 +59,8 @@ public class Brimstone extends Armor.Glyph { if (hero.buff(Burning.class) != null){ //max shielding equal to the armors level (this does mean no shield at lvl 0) - if (hero.SHLD < level) { - shieldAdded++; - hero.SHLD++; - lastShield++; + if (shielding < level) { + shielding++; //generates 0.2 + 0.1*lvl shield per turn spend( 10f / (2f + level)); @@ -83,10 +71,8 @@ public class Brimstone extends Armor.Glyph { } } else if (hero.buff(Burning.class) == null){ - if (shieldAdded > 0 && hero.SHLD > 0){ - shieldAdded--; - hero.SHLD--; - lastShield--; + if (shielding > 0){ + shielding--; //shield decays at a rate of 1 per turn. spend(TICK); @@ -94,6 +80,7 @@ public class Brimstone extends Armor.Glyph { detach(); } } + target.needsShieldUpdate = true; return true; } @@ -103,21 +90,13 @@ public class Brimstone extends Armor.Glyph { spend(-cooldown()+2); } - private static String ADDED = "added"; - private static String LAST = "last"; - - @Override - public void storeInBundle(Bundle bundle) { - super.storeInBundle(bundle); - bundle.put( ADDED, shieldAdded ); - bundle.put( LAST, lastShield ); - } - @Override public void restoreFromBundle(Bundle bundle) { super.restoreFromBundle(bundle); - shieldAdded = bundle.getInt( ADDED ); - lastShield = bundle.getInt( LAST ); + //pre-0.7.0 + if (bundle.contains("added")){ + shielding = bundle.getInt("added"); + } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfShielding.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfShielding.java index f11685489..57888e066 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfShielding.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfShielding.java @@ -21,6 +21,17 @@ package com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; + public class PotionOfShielding extends ExoticPotion { - //TODO + + @Override + public void apply(Hero hero) { + setKnown(); + + //~75% of a potion of healing + Buff.affect(hero, Barrier.class).set((int)(0.6f*hero.HT + 10)); + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/CharHealthIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/CharHealthIndicator.java index 9b52f8006..f134f369b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/CharHealthIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/CharHealthIndicator.java @@ -52,7 +52,7 @@ public class CharHealthIndicator extends HealthBar { x = sprite.x + sprite.width()/6f; y = sprite.y - 2; level( target ); - visible = target.HP < target.HT || target.SHLD > 0; + visible = target.HP < target.HT || target.shielding() > 0; } else { visible = false; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/HealthBar.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/HealthBar.java index 28b98d8d0..c7071f993 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/HealthBar.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/HealthBar.java @@ -81,7 +81,7 @@ public class HealthBar extends Component { public void level(Char c){ float health = c.HP; - float shield = c.SHLD; + float shield = c.shielding(); float max = Math.max(health+shield, c.HT); level(health/max, (health+shield)/max); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 4f9dc2aa3..12e3336ea 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -187,9 +187,9 @@ public class StatusPane extends Component { @Override public void update() { super.update(); - + float health = Dungeon.hero.HP; - float shield = Dungeon.hero.SHLD; + float shield = Dungeon.hero.shielding(); float max = Dungeon.hero.HT; if (!Dungeon.hero.isAlive()) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java index 160be4ce4..d6bbaaa7f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java @@ -113,7 +113,7 @@ public class WndHero extends WndTabbed { pos = title.bottom() + 2*GAP; statSlot( Messages.get(this, "str"), hero.STR() ); - if (hero.SHLD > 0) statSlot( Messages.get(this, "health"), hero.HP + "+" + hero.SHLD + "/" + hero.HT ); + if (hero.shielding() > 0) statSlot( Messages.get(this, "health"), hero.HP + "+" + hero.shielding() + "/" + hero.HT ); else statSlot( Messages.get(this, "health"), (hero.HP) + "/" + hero.HT ); statSlot( Messages.get(this, "exp"), hero.exp + "/" + hero.maxExp() );