From ec6e88139cd5b36033bbc5c2c2ad510a97da54ad Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 30 Jun 2018 20:42:26 -0400 Subject: [PATCH] v0.7.0: rebalanced wand of transmutation, added a barrier buff --- .../actors/buffs/Barrier.java | 84 +++++++++++++ .../effects/ShieldHalo.java | 79 ++++++++++++ .../items/wands/WandOfTransfusion.java | 116 +++++------------- .../sprites/CharSprite.java | 21 +++- .../sprites/HeroSprite.java | 8 +- .../sprites/WandmakerSprite.java | 62 +--------- .../ui/CharHealthIndicator.java | 2 +- .../messages/items/items.properties | 2 +- 8 files changed, 223 insertions(+), 151 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/ShieldHalo.java 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 new file mode 100644 index 000000000..2cad768d8 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Barrier.java @@ -0,0 +1,84 @@ +/* + * 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.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; + + //TODO icon and description for phase 2 + + @Override + public boolean act() { + + if (target.SHLD == level){ + target.SHLD -= 1; + } + + level -= 1; + + if (target.SHLD <= level) { + target.SHLD = level; + } + + if (level <= 0){ + detach(); + } + + spend( TICK ); + + return true; + } + + public void set( int shielding ){ + if (level < shielding){ + level = shielding; + if (target.SHLD < level){ + target.SHLD = level; + } + } + } + + @Override + public void fx(boolean on) { + if (on) target.sprite.add(CharSprite.State.SHIELDED); + 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 ); + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/ShieldHalo.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/ShieldHalo.java new file mode 100644 index 000000000..916a7e95e --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/effects/ShieldHalo.java @@ -0,0 +1,79 @@ +/* + * 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.effects; + +import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; +import com.watabou.glwrap.Blending; +import com.watabou.noosa.Game; +import com.watabou.utils.PointF; + +public class ShieldHalo extends Halo { + + private CharSprite target; + + private float phase; + + public ShieldHalo( CharSprite sprite ) { + + //rectangular sprite to circular radius. Pythagorean theorem + super( (float)Math.sqrt(Math.pow(sprite.width()/2f, 2) + Math.pow(sprite.height()/2f, 2)), 0xBBAACC, 1f ); + + am = -0.33f; + aa = +0.33f; + + target = sprite; + + phase = 1; + } + + @Override + public void update() { + super.update(); + + if (phase < 1) { + if ((phase -= Game.elapsed) <= 0) { + killAndErase(); + } else { + scale.set( (2 - phase) * radius / RADIUS ); + am = phase * (-1); + aa = phase * (+1); + } + } + + if (visible = target.visible) { + PointF p = target.center(); + point( p.x, p.y ); + } + } + + @Override + public void draw() { + Blending.setLightMode(); + super.draw(); + Blending.setNormalMode(); + } + + public void putOut() { + phase = 0.999f; + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java index 284732ec5..1c3f796ff 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTransfusion.java @@ -25,6 +25,7 @@ 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.Barrier; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; @@ -32,18 +33,10 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Beam; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.BloodParticle; -import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle; -import com.shatteredpixel.shatteredpixeldungeon.items.Generator; -import com.shatteredpixel.shatteredpixeldungeon.items.Heap; -import com.shatteredpixel.shatteredpixeldungeon.items.Item; -import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring; import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff; -import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; -import com.shatteredpixel.shatteredpixeldungeon.plants.Plant; -import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap; @@ -73,105 +66,64 @@ public class WandOfTransfusion extends Wand { int cell = beam.collisionPos; Char ch = Actor.findChar(cell); - Heap heap = Dungeon.level.heaps.get(cell); - //this wand does a bunch of different things depending on what it targets. - - //if we find a character.. if (ch != null && ch instanceof Mob){ + + // 10% of max hp + int selfDmg = (int)Math.ceil(curUser.HT*0.10f); processSoulMark(ch, chargesPerCast()); - - //heals an ally, or a charmed enemy + + //this wand does different things depending on the target. + + //heals/shields an ally, or a charmed enemy if (ch.alignment == Char.Alignment.ALLY || ch.buff(Charm.class) != null){ - - int missingHP = ch.HT - ch.HP; - //heals 30%+3%*lvl missing HP. - int healing = (int)Math.ceil((missingHP * (0.30f+(0.03f*level())))); + + int healing = selfDmg + 3*level(); + int shielding = -(ch.HT - ch.HP - healing); + if (shielding > 0){ + healing -= shielding; + } + ch.HP += healing; - ch.sprite.emitter().burst(Speck.factory(Speck.HEALING), 1 + level() / 2); - ch.sprite.showStatus(CharSprite.POSITIVE, "+%dHP", healing); + + Buff.affect(ch, Barrier.class).set(shielding); + + ch.sprite.emitter().burst(Speck.factory(Speck.HEALING), 2 + level() / 2); + ch.sprite.showStatus(CharSprite.POSITIVE, "+%dHP", healing + shielding); //harms the undead } else if (ch.properties().contains(Char.Property.UNDEAD)){ - - //deals 30%+5%*lvl total HP. - int damage = (int) Math.ceil(ch.HT*(0.3f+(0.05f*level()))); + + int damage = selfDmg + 3*level(); ch.damage(damage, this); ch.sprite.emitter().start(ShadowParticle.UP, 0.05f, 10 + level()); Sample.INSTANCE.play(Assets.SND_BURNING); //charms an enemy } else { - - float duration = 5+level(); - Buff.affect(ch, Charm.class, duration).object = curUser.id(); - - duration *= Random.Float(0.75f, 1f); - Buff.affect(curUser, Charm.class, duration).object = ch.id(); + + Buff.affect(ch , Charm.class, 5 + level() ).object = curUser.id(); + Buff.affect(curUser , Charm.class, 5 ).object = ch.id(); ch.sprite.centerEmitter().start( Speck.factory( Speck.HEART ), 0.2f, 5 ); curUser.sprite.centerEmitter().start( Speck.factory( Speck.HEART ), 0.2f, 5 ); } - - - //if we find an item... - } else if (heap != null && heap.type == Heap.Type.HEAP){ - Item item = heap.peek(); - - //30% + 10%*lvl chance to uncurse the item and reset it to base level if degraded. - if (item != null && Random.Float() <= 0.3f+level()*0.1f){ - if (item.cursed){ - item.cursed = false; - CellEmitter.get(cell).start( ShadowParticle.UP, 0.05f, 10 ); - Sample.INSTANCE.play(Assets.SND_BURNING); - } - - int lvldiffFromBase = item.level() - (item instanceof Ring ? 1 : 0); - if (lvldiffFromBase < 0){ - item.upgrade(-lvldiffFromBase); - CellEmitter.get(cell).start(Speck.factory(Speck.UP), 0.2f, 3); - Sample.INSTANCE.play(Assets.SND_BURNING); - } + + if (!freeCharge) { + damageHero(selfDmg); + } else { + freeCharge = false; } - - //if we find some trampled grass... - } else if (Dungeon.level.map[cell] == Terrain.GRASS) { - - //regrow one grass tile, suuuuuper useful... - Dungeon.level.set(cell, Terrain.HIGH_GRASS); - GameScene.updateMap(cell); - CellEmitter.get( cell ).burst(LeafParticle.LEVEL_SPECIFIC, 4); - - //If we find embers... - } else if (Dungeon.level.map[cell] == Terrain.EMBERS) { - - //30% + 3%*lvl chance to grow a random plant, or just regrow grass. - if (Random.Float() <= 0.3f+level()*0.03f) { - Dungeon.level.plant((Plant.Seed) Generator.random(Generator.Category.SEED), cell); - CellEmitter.get( cell ).burst(LeafParticle.LEVEL_SPECIFIC, 8); - GameScene.updateMap(cell); - } else{ - Dungeon.level.set(cell, Terrain.HIGH_GRASS); - GameScene.updateMap(cell); - CellEmitter.get( cell ).burst(LeafParticle.LEVEL_SPECIFIC, 4); - } - - } else - return; //don't damage the hero if we can't find a target; - - if (!freeCharge) { - damageHero(); - } else { - freeCharge = false; + } + } //this wand costs health too - private void damageHero(){ - // 10% of max hp - int damage = (int)Math.ceil(curUser.HT*0.10f); + private void damageHero(int damage){ + curUser.damage(damage, this); if (!curUser.isAlive()){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java index c52ec7cce..73ee1cb12 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java @@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.DarkBlock; import com.shatteredpixel.shatteredpixeldungeon.effects.EmoIcon; import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText; import com.shatteredpixel.shatteredpixeldungeon.effects.IceBlock; +import com.shatteredpixel.shatteredpixeldungeon.effects.ShieldHalo; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.Splash; import com.shatteredpixel.shatteredpixeldungeon.effects.TorchHalo; @@ -78,7 +79,7 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip protected float shadowOffset = 0.25f; public enum State { - BURNING, LEVITATING, INVISIBLE, PARALYSED, FROZEN, ILLUMINATED, CHILLED, DARKENED, MARKED, HEALING + BURNING, LEVITATING, INVISIBLE, PARALYSED, FROZEN, ILLUMINATED, CHILLED, DARKENED, MARKED, HEALING, SHIELDED } protected Animation idle; @@ -100,7 +101,8 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip protected IceBlock iceBlock; protected DarkBlock darkBlock; - protected TorchHalo halo; + protected TorchHalo light; + protected ShieldHalo shield; protected AlphaTweener invisible; protected EmoIcon emo; @@ -331,7 +333,7 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip paused = true; break; case ILLUMINATED: - GameScene.effect( halo = new TorchHalo( this ) ); + GameScene.effect( light = new TorchHalo( this ) ); break; case CHILLED: chilled = emitter(); @@ -347,6 +349,10 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip case HEALING: healing = emitter(); healing.pour(Speck.factory(Speck.HEALING), 0.5f); + break; + case SHIELDED: + GameScene.effect( shield = new ShieldHalo( this )); + break; } } @@ -382,8 +388,8 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip paused = false; break; case ILLUMINATED: - if (halo != null) { - halo.putOut(); + if (light != null) { + light.putOut(); } break; case CHILLED: @@ -410,6 +416,11 @@ public class CharSprite extends MovieClip implements Tweener.Listener, MovieClip healing = null; } break; + case SHIELDED: + if (shield != null){ + shield.putOut(); + } + break; } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java index 011ac3a01..ab4306c66 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/HeroSprite.java @@ -49,10 +49,10 @@ public class HeroSprite extends CharSprite { public HeroSprite() { super(); - link( Dungeon.hero ); - texture( Dungeon.hero.heroClass.spritesheet() ); updateArmor(); + + link( Dungeon.hero ); if (ch.isAlive()) idle(); @@ -62,7 +62,7 @@ public class HeroSprite extends CharSprite { public void updateArmor() { - TextureFilm film = new TextureFilm( tiers(), ((Hero)ch).tier(), FRAME_WIDTH, FRAME_HEIGHT ); + TextureFilm film = new TextureFilm( tiers(), Dungeon.hero.tier(), FRAME_WIDTH, FRAME_HEIGHT ); idle = new Animation( 1, true ); idle.frames( film, 0, 0, 0, 1, 0, 0, 1, 1 ); @@ -87,7 +87,7 @@ public class HeroSprite extends CharSprite { read = new Animation( 20, false ); read.frames( film, 19, 20, 20, 20, 20, 20, 20, 20, 20, 19 ); - if (ch.isAlive()) + if (Dungeon.hero.isAlive()) idle(); else die(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/WandmakerSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/WandmakerSprite.java index 87cd5d543..b4b08bbe3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/WandmakerSprite.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/WandmakerSprite.java @@ -23,17 +23,14 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; -import com.shatteredpixel.shatteredpixeldungeon.effects.Halo; +import com.shatteredpixel.shatteredpixeldungeon.effects.ShieldHalo; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle; -import com.watabou.glwrap.Blending; -import com.watabou.noosa.Game; import com.watabou.noosa.TextureFilm; import com.watabou.noosa.audio.Sample; -import com.watabou.utils.PointF; public class WandmakerSprite extends MobSprite { - private Shield shield; + private ShieldHalo shield; public WandmakerSprite() { super(); @@ -57,70 +54,19 @@ public class WandmakerSprite extends MobSprite { @Override public void link( Char ch ) { super.link( ch ); - - if (shield == null) { - parent.add( shield = new Shield() ); - } + add(State.SHIELDED); } @Override public void die() { super.die(); - if (shield != null) { - shield.putOut(); - } + remove(State.SHIELDED); emitter().start( ElmoParticle.FACTORY, 0.03f, 60 ); if (visible) { Sample.INSTANCE.play( Assets.SND_BURNING ); } } - - public class Shield extends Halo { - - private float phase; - - public Shield() { - - super( 9, 0xBBAACC, 1f ); - - am = -0.33f; - aa = +0.33f; - - phase = 1; - } - - @Override - public void update() { - super.update(); - - if (phase < 1) { - if ((phase -= Game.elapsed) <= 0) { - killAndErase(); - } else { - scale.set( (2 - phase) * radius / RADIUS ); - am = phase * (-1); - aa = phase * (+1); - } - } - - if (visible = WandmakerSprite.this.visible) { - PointF p = WandmakerSprite.this.center(); - point(p.x, p.y ); - } - } - - @Override - public void draw() { - Blending.setLightMode(); - super.draw(); - Blending.setNormalMode(); - } - - public void putOut() { - phase = 0.999f; - } - } } 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 6cec7d4e6..9b52f8006 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; + visible = target.HP < target.HT || target.SHLD > 0; } else { visible = false; } 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 8afb403ea..ae9768ff3 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 @@ -810,7 +810,7 @@ items.wands.wandoftransfusion.staff_name=staff of transfusion items.wands.wandoftransfusion.ondeath=You killed yourself with your own Wand of Transfusion... items.wands.wandoftransfusion.charged=Your staff is charged with the life energy of your enemy! items.wands.wandoftransfusion.desc=A fairly plainly shaped wand, it stands out due to its magenta hue and pitch black gem at the tip. -items.wands.wandoftransfusion.stats_desc=This wand will take some of your life energy and blast it at a target. This effect is very versatile: allies will be healed, enemies will be temporarily charmed, and hostile undead will take considerable damage. The life drain is significant though, using this wand will deal damage to you in addition to consuming charges. +items.wands.wandoftransfusion.stats_desc=This wand will sap some of your life energy and blast it at a target. This effect is very versatile: allies will be healed or shielded, enemies will be temporarily charmed, and hostile undead will take considerable damage. items.wands.wandofcorrosion.name=wand of corrosion items.wands.wandofcorrosion.staff_name=staff of corrosion