From 16822095df09569868eb4cd329c14202abfc04c3 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 22 Jul 2020 00:48:33 -0400 Subject: [PATCH] v0.8.2: improvements to cone AOEs and fireblast: - items which use cones can now trickshot - fireblast now bursts open doors instead of colliding with them --- .../items/artifacts/TalismanOfForesight.java | 2 +- .../potions/exotic/PotionOfDragonsBreath.java | 25 ++++++++++++++++--- .../items/wands/WandOfFireblast.java | 22 +++++++++++++--- .../items/wands/WandOfRegrowth.java | 2 +- .../mechanics/Ballistica.java | 24 ++++++++++++++---- .../mechanics/ConeAOE.java | 24 +++++++++++++----- 6 files changed, 80 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TalismanOfForesight.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TalismanOfForesight.java index cdb3e77cf..8784207ce 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TalismanOfForesight.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TalismanOfForesight.java @@ -144,7 +144,7 @@ public class TalismanOfForesight extends Artifact { //starts at 200 degrees, loses 8% per tile of distance float angle = Math.round(200*(float)Math.pow(0.92, dist)); - ConeAOE cone = new ConeAOE(curUser.pos, target, angle); + ConeAOE cone = new ConeAOE(new Ballistica(curUser.pos, target, Ballistica.STOP_TARGET), angle); int earnedExp = 0; boolean noticed = false; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfDragonsBreath.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfDragonsBreath.java index 3c933c13a..97a897ca2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfDragonsBreath.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/potions/exotic/PotionOfDragonsBreath.java @@ -40,6 +40,9 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.watabou.noosa.audio.Sample; import com.watabou.utils.Callback; +import com.watabou.utils.PathFinder; + +import java.util.ArrayList; public class PotionOfDragonsBreath extends ExoticPotion { @@ -77,12 +80,12 @@ public class PotionOfDragonsBreath extends ExoticPotion { curUser.sprite.zap(cell); Sample.INSTANCE.play( Assets.Sounds.BURNING ); - final Ballistica bolt = new Ballistica(curUser.pos, cell, Ballistica.STOP_TERRAIN); + final Ballistica bolt = new Ballistica(curUser.pos, cell, Ballistica.STOP_TERRAIN | Ballistica.OPEN_DOORS); int maxDist = 6; int dist = Math.min(bolt.dist, maxDist); - final ConeAOE cone = new ConeAOE(curUser.pos, bolt.path.get(dist), 6, 60, Ballistica.STOP_TERRAIN | Ballistica.STOP_TARGET ); + final ConeAOE cone = new ConeAOE(bolt, 6, 60, Ballistica.STOP_TERRAIN | Ballistica.STOP_TARGET | Ballistica.OPEN_DOORS ); //cast to cells at the tip, rather than all cells, better performance. for (Ballistica ray : cone.rays){ @@ -101,6 +104,7 @@ public class PotionOfDragonsBreath extends ExoticPotion { new Callback() { @Override public void call() { + ArrayList adjacentCells = new ArrayList<>(); for (int cell : cone.cells){ //ignore caster cell if (cell == bolt.sourcePos){ @@ -108,7 +112,9 @@ public class PotionOfDragonsBreath extends ExoticPotion { } //only ignite cells directly near caster if they are flammable - if (!Dungeon.level.adjacent(bolt.sourcePos, cell) || Dungeon.level.flamable[cell]){ + if (Dungeon.level.adjacent(bolt.sourcePos, cell) && !Dungeon.level.flamable[cell]){ + adjacentCells.add(cell); + } else { GameScene.add( Blob.seed( cell, 5, Fire.class ) ); } @@ -119,6 +125,19 @@ public class PotionOfDragonsBreath extends ExoticPotion { Buff.affect(ch, Cripple.class, 5f); } } + + //ignite cells that share a side with an adjacent cell, are flammable, and are further from the source pos + //This prevents short-range casts not igniting barricades or bookshelves + for (int cell : adjacentCells){ + for (int i : PathFinder.NEIGHBOURS4){ + if (Dungeon.level.trueDistance(cell+i, bolt.sourcePos) > Dungeon.level.trueDistance(cell, bolt.sourcePos) + && Dungeon.level.flamable[cell+i] + && Fire.volumeAt(cell+i, Fire.class) == 0){ + GameScene.add( Blob.seed( cell+i, 5, Fire.class ) ); + } + } + } + curUser.next(); } }); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFireblast.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFireblast.java index c7858d74a..268c796ee 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFireblast.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFireblast.java @@ -41,6 +41,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.watabou.noosa.audio.Sample; import com.watabou.utils.Callback; +import com.watabou.utils.PathFinder; import java.util.ArrayList; @@ -49,7 +50,7 @@ public class WandOfFireblast extends DamageWand { { image = ItemSpriteSheet.WAND_FIREBOLT; - collisionProperties = Ballistica.STOP_TERRAIN; + collisionProperties = Ballistica.STOP_TERRAIN | Ballistica.OPEN_DOORS; } //1x/2x/3x damage @@ -68,6 +69,7 @@ public class WandOfFireblast extends DamageWand { protected void onZap( Ballistica bolt ) { ArrayList affectedChars = new ArrayList<>(); + ArrayList adjacentCells = new ArrayList<>(); for( int cell : cone.cells ){ //ignore caster cell @@ -76,7 +78,9 @@ public class WandOfFireblast extends DamageWand { } //only ignite cells directly near caster if they are flammable - if (!Dungeon.level.adjacent(bolt.sourcePos, cell) || Dungeon.level.flamable[cell]){ + if (Dungeon.level.adjacent(bolt.sourcePos, cell) && !Dungeon.level.flamable[cell]){ + adjacentCells.add(cell); + } else { GameScene.add( Blob.seed( cell, 1+chargesPerCast(), Fire.class ) ); } @@ -86,6 +90,18 @@ public class WandOfFireblast extends DamageWand { } } + //ignite cells that share a side with an adjacent cell, are flammable, and are further from the source pos + //This prevents short-range casts not igniting barricades or bookshelves + for (int cell : adjacentCells){ + for (int i : PathFinder.NEIGHBOURS4){ + if (Dungeon.level.trueDistance(cell+i, bolt.sourcePos) > Dungeon.level.trueDistance(cell, bolt.sourcePos) + && Dungeon.level.flamable[cell+i] + && Fire.volumeAt(cell+i, Fire.class) == 0){ + GameScene.add( Blob.seed( cell+i, 1+chargesPerCast(), Fire.class ) ); + } + } + } + for ( Char ch : affectedChars ){ processSoulMark(ch, chargesPerCast()); ch.damage(damageRoll(), this); @@ -119,7 +135,7 @@ public class WandOfFireblast extends DamageWand { int maxDist = 2 + 2*chargesPerCast(); int dist = Math.min(bolt.dist, maxDist); - cone = new ConeAOE( bolt.sourcePos, bolt.path.get(dist), + cone = new ConeAOE( bolt, maxDist, 30 + 20*chargesPerCast(), collisionProperties | Ballistica.STOP_TARGET); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java index ff551813b..5560f842c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java @@ -203,7 +203,7 @@ public class WandOfRegrowth extends Wand { int maxDist = 2 + 2*chargesPerCast(); int dist = Math.min(bolt.dist, maxDist); - cone = new ConeAOE( bolt.sourcePos, bolt.path.get(dist), + cone = new ConeAOE( bolt, maxDist, 20 + 10*chargesPerCast(), collisionProperties | Ballistica.STOP_TARGET); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java index 9c0ca3615..66b77d38b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java @@ -24,6 +24,9 @@ package com.shatteredpixel.shatteredpixeldungeon.mechanics; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import java.util.ArrayList; import java.util.List; @@ -38,9 +41,10 @@ public class Ballistica { public Integer dist = 0; //parameters to specify the colliding cell - public static final int STOP_TARGET = 1; //ballistica will stop at the target cell - public static final int STOP_CHARS = 2; //ballistica will stop on first char hit - public static final int STOP_TERRAIN = 4; //ballistica will stop on terrain(LOS blocking, impassable, etc.) + public static final int STOP_TARGET = 1; //ballistica will stop at the target cell + public static final int STOP_CHARS = 2; //ballistica will stop on first char hit + public static final int STOP_TERRAIN = 4; //ballistica will stop on solid terrain + public static final int OPEN_DOORS = 8; //ballistica will open doors instead of colliding public static final int PROJECTILE = STOP_TARGET | STOP_CHARS | STOP_TERRAIN; @@ -51,7 +55,12 @@ public class Ballistica { public Ballistica( int from, int to, int params ){ sourcePos = from; - build(from, to, (params & STOP_TARGET) > 0, (params & STOP_CHARS) > 0, (params & STOP_TERRAIN) > 0); + build(from, to, + (params & STOP_TARGET) > 0, + (params & STOP_CHARS) > 0, + (params & STOP_TERRAIN) > 0, + (params & OPEN_DOORS) > 0); + if (collisionPos != null) { dist = path.indexOf(collisionPos); } else if (!path.isEmpty()) { @@ -63,7 +72,7 @@ public class Ballistica { } } - private void build( int from, int to, boolean stopTarget, boolean stopChars, boolean stopTerrain ) { + private void build( int from, int to, boolean stopTarget, boolean stopChars, boolean stopTerrain, boolean openDoors ) { int w = Dungeon.level.width(); int x0 = from % w; @@ -114,6 +123,11 @@ public class Ballistica { path.add(cell); + if (openDoors && collisionPos == null && Dungeon.level.map[cell] == Terrain.DOOR){ + Level.set(cell, Terrain.OPEN_DOOR); + GameScene.updateMap(cell); + } + if ((stopTerrain && cell != sourcePos && Dungeon.level.solid[cell]) || (cell != sourcePos && stopChars && Actor.findChar( cell ) != null) || (cell == to && stopTarget)){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/ConeAOE.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/ConeAOE.java index 30d28cf1f..7f9253f62 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/ConeAOE.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/mechanics/ConeAOE.java @@ -33,21 +33,26 @@ import java.util.LinkedHashSet; //a cone made of up several ballisticas scanning in an arc public class ConeAOE { + public Ballistica coreRay; + public ArrayList rays = new ArrayList<>(); public HashSet cells = new HashSet<>(); - public ConeAOE( int from, int to, float degrees ){ - this(from, to, Float.POSITIVE_INFINITY, degrees, Ballistica.STOP_TARGET); + public ConeAOE( Ballistica core, float degrees ){ + this( core, Float.POSITIVE_INFINITY, degrees, Ballistica.STOP_TARGET/* TODO */); } - public ConeAOE( int from, int to, float maxDist, float degrees, int ballisticaParams ){ + public ConeAOE( Ballistica core, float maxDist, float degrees, int ballisticaParams ){ + + coreRay = core; //we want to use true coordinates for our trig functions, not game cells // so get the center of from and to as points - PointF fromP = new PointF(Dungeon.level.cellToPoint(from)); + PointF fromP = new PointF(Dungeon.level.cellToPoint(core.sourcePos)); fromP.x += 0.5f; fromP.y += 0.5f; - PointF toP = new PointF(Dungeon.level.cellToPoint(to)); + + PointF toP = new PointF(Dungeon.level.cellToPoint(core.collisionPos)); toP.x += 0.5f; toP.y += 0.5f; @@ -94,11 +99,18 @@ public class ConeAOE { //cast a ray to each found cell, these make up the cone for( int c : targetCells ){ - Ballistica ray = new Ballistica(from, c, ballisticaParams); + Ballistica ray = new Ballistica(core.sourcePos, c, ballisticaParams); cells.addAll(ray.subPath(1, ray.dist)); rays.add(ray); } + //lastly add any cells in the core + for ( int c : core.subPath(1, core.dist)){ + if (Dungeon.level.trueDistance(core.sourcePos, c) <= maxDist){ + cells.add(c); + } + } + } }