From 4b680c93add3a67245130e6102a71837cd3528cc Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 1 May 2015 07:46:14 -0400 Subject: [PATCH] v0.3.0: reworked lightning effect and wand of lightning --- .../effects/Lightning.java | 135 +++++++++--------- .../items/armor/glyphs/Potential.java | 5 +- .../items/wands/WandOfLightning.java | 96 +++++++------ .../items/weapon/enchantments/Shock.java | 37 ++--- .../levels/traps/LightningTrap.java | 18 ++- .../sprites/ShamanSprite.java | 8 +- 6 files changed, 149 insertions(+), 150 deletions(-) diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/effects/Lightning.java b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Lightning.java index 9b340776c..e69557f57 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/effects/Lightning.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/effects/Lightning.java @@ -27,61 +27,37 @@ import com.watabou.noosa.Image; import com.watabou.noosa.audio.Sample; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.DungeonTilemap; -import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.watabou.utils.Callback; +import com.watabou.utils.PointF; import com.watabou.utils.Random; +import java.util.Arrays; +import java.util.List; + public class Lightning extends Group { private static final float DURATION = 0.3f; private float life; - - private int length; - private float[] cx; - private float[] cy; - - private Image[] arcsS; - private Image[] arcsE; + + private List arcs; private Callback callback; + + public Lightning(int from, int to, Callback callback){ + this(Arrays.asList(new Arc(from, to)), callback); + } - public Lightning( int[] cells, int length, Callback callback ) { + public Lightning( List arcs, Callback callback ) { super(); - + + this.arcs = arcs; + for (Arc arc : this.arcs) + add(arc); + this.callback = callback; - Image proto = Effects.get( Effects.Type.LIGHTNING ); - float ox = 0; - float oy = proto.height / 2; - - this.length = length; - cx = new float[length]; - cy = new float[length]; - - for (int i=0; i < length; i++) { - int c = cells[i]; - cx[i] = (c % Level.WIDTH + 0.5f) * DungeonTilemap.SIZE; - cy[i] = (c / Level.WIDTH + 0.5f) * DungeonTilemap.SIZE; - } - - arcsS = new Image[length - 1]; - arcsE = new Image[length - 1]; - for (int i=0; i < length - 1; i++) { - - Image arc = arcsS[i] = new Image( proto ); - - arc.x = cx[i] - arc.origin.x; - arc.y = cy[i] - arc.origin.y; - arc.origin.set( ox, oy ); - add( arc ); - - arc = arcsE[i] = new Image( proto ); - arc.origin.set( ox, oy ); - add( arc ); - } - life = DURATION; Sample.INSTANCE.play( Assets.SND_LIGHTNING ); @@ -91,8 +67,6 @@ public class Lightning extends Group { @Override public void update() { - super.update(); - if ((life -= Game.elapsed) < 0) { killAndErase(); @@ -104,32 +78,11 @@ public class Lightning extends Group { float alpha = life / DURATION; - for (int i=0; i < length - 1; i++) { - - float sx = cx[i]; - float sy = cy[i]; - float ex = cx[i+1]; - float ey = cy[i+1]; - - float x2 = (sx + ex) / 2 + Random.Float( -4, +4 ); - float y2 = (sy + ey) / 2 + Random.Float( -4, +4 ); - - float dx = x2 - sx; - float dy = y2 - sy; - Image arc = arcsS[i]; - arc.am = alpha; - arc.angle = (float)(Math.atan2( dy, dx ) * A); - arc.scale.x = (float)Math.sqrt( dx * dx + dy * dy ) / arc.width; - - dx = ex - x2; - dy = ey - y2; - arc = arcsE[i]; - arc.am = alpha; - arc.angle = (float)(Math.atan2( dy, dx ) * A); - arc.scale.x = (float)Math.sqrt( dx * dx + dy * dy ) / arc.width; - arc.x = x2 - arc.origin.x; - arc.y = y2 - arc.origin.x; + for (Arc arc : arcs) { + arc.alpha(alpha); } + + super.update(); } } @@ -139,4 +92,52 @@ public class Lightning extends Group { super.draw(); GLES20.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA ); } + + //A lightning object is meant to be loaded up with arcs. + //these act as a means of easily expressing lighting between two points. + public static class Arc extends Group { + + private Image arc1, arc2; + + //starting and ending x/y values + private PointF start, end; + + public Arc(int from, int to){ + start = DungeonTilemap.tileCenterToWorld(from); + end = DungeonTilemap.tileCenterToWorld(to); + + arc1 = new Image(Effects.get(Effects.Type.LIGHTNING)); + arc1.x = start.x - arc1.origin.x; + arc1.y = start.y - arc1.origin.y; + arc1.origin.set( 0, arc1.height()/2 ); + add( arc1 ); + + arc2 = new Image(Effects.get(Effects.Type.LIGHTNING)); + arc2.origin.set( 0, arc2.height()/2 ); + add( arc2 ); + + } + + public void alpha(float alpha) { + arc1.am = arc2.am = alpha; + } + + @Override + public void update() { + float x2 = (start.x + end.x) / 2 + Random.Float( -4, +4 ); + float y2 = (start.y + end.y) / 2 + Random.Float( -4, +4 ); + + float dx = x2 - start.x; + float dy = y2 - start.y; + arc1.angle = (float)(Math.atan2( dy, dx ) * A); + arc1.scale.x = (float)Math.sqrt( dx * dx + dy * dy ) / arc1.width; + + dx = end.x - x2; + dy = end.y - y2; + arc2.angle = (float)(Math.atan2( dy, dx ) * A); + arc2.scale.x = (float)Math.sqrt( dx * dx + dy * dy ) / arc2.width; + arc2.x = x2 - arc2.origin.x; + arc2.y = y2 - arc2.origin.x; + } + } } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Potential.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Potential.java index 763ec38f2..ecccd5fe1 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Potential.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/Potential.java @@ -51,9 +51,8 @@ public class Potential extends Glyph { if (defender == Dungeon.hero) { Camera.main.shake( 2, 0.3f ); } - - int[] points = {attacker.pos, defender.pos}; - attacker.sprite.parent.add( new Lightning( points, 2, null ) ); + + attacker.sprite.parent.add( new Lightning( attacker.pos, defender.pos, null ) ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java index 47e652fb8..122ad5a0f 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java @@ -46,14 +46,28 @@ public class WandOfLightning extends Wand { image = ItemSpriteSheet.WAND_LIGHTNING; } - private ArrayList affected = new ArrayList(); - - private int[] points = new int[20]; - private int nPoints; + private ArrayList affected = new ArrayList<>(); + + ArrayList arcs = new ArrayList<>(); @Override protected void onZap( Ballistica bolt ) { - // Everything is processed in fx() method + + //lightning deals less damage per-target, the more targets that are hit. + float multipler = (0.6f + 0.4f*affected.size())/affected.size(); + if (Level.water[bolt.collisionPos]) multipler *= 1.5f; + + int min = 5+level; + int max = Math.round(10 + (level * level / 4f)); + + for (Char ch : affected){ + ch.damage(Math.round(Random.NormalIntRange(min, max) * multipler), LightningTrap.LIGHTNING); + + if (ch == Dungeon.hero) Camera.main.shake( 2, 0.3f ); + ch.sprite.centerEmitter().burst( SparkParticle.FACTORY, 3 ); + ch.sprite.flash(); + } + if (!curUser.isAlive()) { Dungeon.fail( Utils.format( ResultDescriptions.ITEM, name ) ); GLog.n( "You killed yourself with your own Wand of Lightning..." ); @@ -66,65 +80,63 @@ public class WandOfLightning extends Wand { new Shock().proc(staff, attacker, defender, damage); } - private void hit( Char ch, int damage ) { - - if (damage < 1) { - return; - } - - if (ch == Dungeon.hero) { - Camera.main.shake( 2, 0.3f ); - } + private void arc( Char ch ) { affected.add( ch ); - ch.damage( Level.water[ch.pos] && !ch.flying ? (int)(damage * 2) : damage, LightningTrap.LIGHTNING ); - - ch.sprite.centerEmitter().burst( SparkParticle.FACTORY, 3 ); - ch.sprite.flash(); - - points[nPoints++] = ch.pos; - - HashSet ns = new HashSet(); - for (int i=0; i < Level.NEIGHBOURS8.length; i++) { - Char n = Actor.findChar( ch.pos + Level.NEIGHBOURS8[i] ); + + for (int i : Level.NEIGHBOURS8) { + int cell = ch.pos + i; + + Char n = Actor.findChar( cell ); if (n != null && !affected.contains( n )) { - ns.add( n ); + arcs.add(new Lightning.Arc(ch.pos, n.pos)); + arc(n); } } - - if (ns.size() > 0) { - hit( Random.element( ns ), Random.Int( damage / 2, damage ) ); + + if (Level.water[ch.pos] && !ch.flying){ + for (int i : Level.NEIGHBOURS8DIST2) { + int cell = ch.pos + i; + //player can only be hit by lightning from an adjacent enemy. + if (!Level.insideMap(cell) || Actor.findChar(cell) == Dungeon.hero) continue; + + Char n = Actor.findChar( ch.pos + i ); + if (n != null && !affected.contains( n )) { + arcs.add(new Lightning.Arc(ch.pos, n.pos)); + arc(n); + } + } } } @Override protected void fx( Ballistica bolt, Callback callback ) { - - nPoints = 0; - points[nPoints++] = Dungeon.hero.pos; + + affected.clear(); + arcs.clear(); + arcs.add( new Lightning.Arc(bolt.sourcePos, bolt.collisionPos)); int cell = bolt.collisionPos; Char ch = Actor.findChar( cell ); if (ch != null) { - - affected.clear(); - int lvl = level(); - hit( ch, Random.Int( 5 + lvl / 2, 10 + lvl ) ); - + arc(ch); } else { - - points[nPoints++] = cell; CellEmitter.center( cell ).burst( SparkParticle.FACTORY, 3 ); - } - curUser.sprite.parent.add( new Lightning( points, nPoints, callback ) ); + + //don't want to wait for the effect before processing damage. + curUser.sprite.parent.add( new Lightning( arcs, null ) ); + callback.call(); } @Override public String desc() { return - "This wand conjures forth deadly arcs of electricity, which deal damage " + - "to several creatures standing close to each other."; + "This wand is made out of solid metal, making it surprisingly heavy. " + + "Two prongs curve together at the top, and electricity arcs between them.\n\n" + + "This wand sends powerful lightning arcing through whatever it is shot at. " + + "This electricity can bounce between many adjacent foes, and is more powerful in water. " + + "If you’re too close, you may get shocked as well."; } } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/weapon/enchantments/Shock.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/weapon/enchantments/Shock.java index f0fe0291a..c08398691 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/weapon/enchantments/Shock.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/weapon/enchantments/Shock.java @@ -42,15 +42,14 @@ public class Shock extends Weapon.Enchantment { if (Random.Int( level + 4 ) >= 3) { - points[0] = attacker.pos; - nPoints = 1; - affected.clear(); - affected.add( attacker ); - - hit( defender, Random.Int( 1, damage / 2 ) ); - - attacker.sprite.parent.add( new Lightning( points, nPoints, null ) ); + affected.add(attacker); + + arcs.clear(); + arcs.add(new Lightning.Arc(attacker.pos, defender.pos)); + hit(defender, Random.Int(1, damage / 2)); + + attacker.sprite.parent.add( new Lightning( arcs, null ) ); return true; @@ -66,10 +65,9 @@ public class Shock extends Weapon.Enchantment { return String.format( TXT_SHOCKING, weaponName ); } - private ArrayList affected = new ArrayList(); - - private int[] points = new int[20]; - private int nPoints; + private ArrayList affected = new ArrayList<>(); + + private ArrayList arcs = new ArrayList<>(); private void hit( Char ch, int damage ) { @@ -77,24 +75,19 @@ public class Shock extends Weapon.Enchantment { return; } - affected.add( ch ); - ch.damage( Level.water[ch.pos] && !ch.flying ? (int)(damage * 2) : damage, LightningTrap.LIGHTNING ); + affected.add(ch); + ch.damage(Level.water[ch.pos] && !ch.flying ? (int) (damage * 2) : damage, LightningTrap.LIGHTNING); - ch.sprite.centerEmitter().burst( SparkParticle.FACTORY, 3 ); + ch.sprite.centerEmitter().burst(SparkParticle.FACTORY, 3); ch.sprite.flash(); - points[nPoints++] = ch.pos; - HashSet ns = new HashSet(); for (int i=0; i < Level.NEIGHBOURS8.length; i++) { Char n = Actor.findChar( ch.pos + Level.NEIGHBOURS8[i] ); if (n != null && !affected.contains( n )) { - ns.add( n ); + arcs.add(new Lightning.Arc(ch.pos, n.pos)); + hit(n, Random.Int(damage / 2, damage)); } } - - if (ns.size() > 0) { - hit( Random.element( ns ), Random.Int( damage / 2, damage ) ); - } } } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/levels/traps/LightningTrap.java b/src/com/shatteredpixel/shatteredpixeldungeon/levels/traps/LightningTrap.java index dcb1a83b5..f35b44540 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/levels/traps/LightningTrap.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/levels/traps/LightningTrap.java @@ -29,6 +29,8 @@ import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.shatteredpixel.shatteredpixeldungeon.utils.Utils; import com.watabou.utils.Random; +import java.util.ArrayList; + public class LightningTrap { private static final String name = "lightning trap"; @@ -48,16 +50,12 @@ public class LightningTrap { GLog.n( "You were killed by a discharge of a lightning trap..." ); } } - - int[] points = new int[2]; - - points[0] = pos - Level.WIDTH; - points[1] = pos + Level.WIDTH; - ch.sprite.parent.add( new Lightning( points, 2, null ) ); - - points[0] = pos - 1; - points[1] = pos + 1; - ch.sprite.parent.add( new Lightning( points, 2, null ) ); + + ArrayList arcs = new ArrayList<>(); + arcs.add(new Lightning.Arc(pos - Level.WIDTH, pos + Level.WIDTH)); + arcs.add(new Lightning.Arc(pos - 1, pos + 1)); + + ch.sprite.parent.add( new Lightning( arcs, null ) ); } CellEmitter.center( pos ).burst( SparkParticle.FACTORY, Random.IntRange( 3, 4 ) ); diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/sprites/ShamanSprite.java b/src/com/shatteredpixel/shatteredpixeldungeon/sprites/ShamanSprite.java index 40a08d8cd..ee46cc98e 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/sprites/ShamanSprite.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/sprites/ShamanSprite.java @@ -24,8 +24,6 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.Lightning; public class ShamanSprite extends MobSprite { - private int[] points = new int[2]; - public ShamanSprite() { super(); @@ -51,10 +49,8 @@ public class ShamanSprite extends MobSprite { } public void zap( int pos ) { - - points[0] = ch.pos; - points[1] = pos; - parent.add( new Lightning( points, 2, (Shaman)ch ) ); + + parent.add( new Lightning( ch.pos, pos, (Shaman)ch ) ); turnTo( ch.pos, pos ); play( zap );