From 99f853c1901c98bbebf6bbf53dcdcf63c828c2bd Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 26 Mar 2015 22:43:23 -0400 Subject: [PATCH] v0.3.0: reworked the ballistica system --- .../actors/mobs/Eye.java | 25 ++-- .../actors/mobs/Goo.java | 4 +- .../actors/mobs/Scorpio.java | 3 +- .../actors/mobs/Shaman.java | 2 +- .../actors/mobs/Succubus.java | 11 +- .../actors/mobs/Tengu.java | 2 +- .../actors/mobs/Warlock.java | 2 +- .../actors/mobs/Yog.java | 2 +- .../actors/mobs/npcs/Ghost.java | 3 +- .../shatteredpixeldungeon/items/Item.java | 2 +- .../items/armor/WarriorArmor.java | 11 +- .../items/wands/Wand.java | 23 ++-- .../items/wands/WandOfAmok.java | 12 +- .../items/wands/WandOfAvalanche.java | 15 ++- .../items/wands/WandOfBlink.java | 15 +-- .../items/wands/WandOfDisintegration.java | 15 +-- .../items/wands/WandOfFirebolt.java | 16 +-- .../items/wands/WandOfFlock.java | 10 +- .../items/wands/WandOfLightning.java | 7 +- .../items/wands/WandOfMagicMissile.java | 5 +- .../items/wands/WandOfPoison.java | 12 +- .../items/wands/WandOfRegrowth.java | 20 +-- .../items/wands/WandOfSlowness.java | 12 +- .../items/wands/WandOfTelekinesis.java | 24 ++-- .../items/wands/WandOfTeleportation.java | 12 +- .../shatteredpixeldungeon/levels/Level.java | 13 +- .../mechanics/Ballistica.java | 114 ++++++++++++------ 27 files changed, 230 insertions(+), 162 deletions(-) diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java index 9b7e3b248..5b951bc46 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Eye.java @@ -64,19 +64,14 @@ public class Eye extends Mob { return 10; } - private int hitCell; + private Ballistica beam; @Override protected boolean canAttack( Char enemy ) { - hitCell = Ballistica.cast( pos, enemy.pos, true, false ); - - for (int i=1; i < Ballistica.distance; i++) { - if (Ballistica.trace[i] == enemy.pos) { - return true; - } - } - return false; + beam = new Ballistica( pos, enemy.pos, Ballistica.STOP_TERRAIN); + + return beam.subPath(1, beam.dist).contains(enemy.pos); } @Override @@ -96,14 +91,14 @@ public class Eye extends Mob { boolean rayVisible = false; - for (int i=0; i < Ballistica.distance; i++) { - if (Dungeon.visible[Ballistica.trace[i]]) { + for (int i : beam.subPath(0, beam.dist)) { + if (Dungeon.visible[i]) { rayVisible = true; } } if (rayVisible) { - sprite.attack( hitCell ); + sprite.attack( beam.collisionPos ); return false; } else { attack( enemy ); @@ -114,10 +109,8 @@ public class Eye extends Mob { @Override public boolean attack( Char enemy ) { - for (int i=1; i < Ballistica.distance; i++) { - - int pos = Ballistica.trace[i]; - + for (int pos : beam.subPath(1, beam.dist)) { + Char ch = Actor.findChar( pos ); if (ch == null) { continue; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java index 3b2d82cf0..9b501fdda 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Goo.java @@ -66,7 +66,7 @@ public class Goo extends Mob { pumpedUp = 0; for (int i = 0; i < Level.NEIGHBOURS9DIST2.length; i++) { int j = pos + Level.NEIGHBOURS9DIST2[i]; - if (j >= 0 && j <= 1023 && Level.passable[j]) + if (Level.insideMap(j) && Level.passable[j]) CellEmitter.get(j).burst(ElmoParticle.FACTORY, 10); } Sample.INSTANCE.play( Assets.SND_BURNING ); @@ -122,7 +122,7 @@ public class Goo extends Mob { ((GooSprite)sprite).pumpUp(); for (int i = 0; i < Level.NEIGHBOURS9DIST2.length; i++) { int j = pos + Level.NEIGHBOURS9DIST2[i]; - if (j >= 0 && j <= 1023 && Level.passable[j]) + if (Level.insideMap(j) && Level.passable[j]) GameScene.add(Blob.seed(j, 2, GooWarn.class)); } pumpedUp++; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java index 9b4d7df37..e8fdca6d5 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Scorpio.java @@ -68,7 +68,8 @@ public class Scorpio extends Mob { @Override protected boolean canAttack( Char enemy ) { - return !Level.adjacent( pos, enemy.pos ) && Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos; + Ballistica attack = new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE); + return !Level.adjacent( pos, enemy.pos ) && attack.collisionPos == enemy.pos; } @Override diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Shaman.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Shaman.java index eb86f1577..38948136d 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Shaman.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Shaman.java @@ -72,7 +72,7 @@ public class Shaman extends Mob implements Callback { @Override protected boolean canAttack( Char enemy ) { - return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos; + return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos; } @Override diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java index 4882ce8f6..0a9425e60 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Succubus.java @@ -92,11 +92,12 @@ public class Succubus extends Mob { private void blink( int target ) { - int cell = Ballistica.cast( pos, target, true, true ); - - if (Actor.findChar( cell ) != null && Ballistica.distance > 1) { - cell = Ballistica.trace[Ballistica.distance - 2]; - } + Ballistica route = new Ballistica( pos, target, Ballistica.PROJECTILE); + int cell = route.collisionPos; + + //can't occupy the same cell as another char, so move back one. + if (Actor.findChar( cell ) != null && cell != this.pos) + cell = route.path.get(route.dist-1); WandOfBlink.appear( this, cell ); diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Tengu.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Tengu.java index cb4a34f44..b82e69e53 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Tengu.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Tengu.java @@ -115,7 +115,7 @@ public class Tengu extends Mob { @Override protected boolean canAttack( Char enemy ) { - return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos; + return new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE).collisionPos == enemy.pos; } @Override diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Warlock.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Warlock.java index b3056eadb..41a1b1c54 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Warlock.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Warlock.java @@ -74,7 +74,7 @@ public class Warlock extends Mob implements Callback { @Override protected boolean canAttack( Char enemy ) { - return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos; + return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos; } protected boolean doAttack( Char enemy ) { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Yog.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Yog.java index 9d667f21f..eebdb1ce2 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Yog.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Yog.java @@ -326,7 +326,7 @@ public class Yog extends Mob { @Override protected boolean canAttack( Char enemy ) { - return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos; + return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos; } @Override diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Ghost.java b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Ghost.java index 2de16f628..24f335d51 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Ghost.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/Ghost.java @@ -467,7 +467,8 @@ public class Ghost extends NPC { @Override protected boolean canAttack( Char enemy ) { - if (!Level.adjacent(pos, enemy.pos) && Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos){ + Ballistica attack = new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE ); + if (!Level.adjacent(pos, enemy.pos) && attack.collisionPos == enemy.pos){ combo++; return true; } else { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/Item.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/Item.java index db5a19d77..c381d18a7 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/Item.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/Item.java @@ -452,7 +452,7 @@ public class Item implements Bundlable { public void cast( final Hero user, int dst ) { - final int cell = Ballistica.cast( user.pos, dst, false, true ); + final int cell = new Ballistica( user.pos, dst, Ballistica.PROJECTILE ).collisionPos; user.sprite.zap( cell ); user.busy(); diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/WarriorArmor.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/WarriorArmor.java index f4eae705f..8fc8b9915 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/WarriorArmor.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/armor/WarriorArmor.java @@ -83,10 +83,13 @@ public class WarriorArmor extends ClassArmor { public void onSelect( Integer target ) { if (target != null && target != curUser.pos) { - int cell = Ballistica.cast( curUser.pos, target, false, true ); - if (Actor.findChar( cell ) != null && cell != curUser.pos) { - cell = Ballistica.trace[Ballistica.distance - 2]; - } + Ballistica route = new Ballistica(curUser.pos, target, Ballistica.PROJECTILE); + int cell = route.collisionPos; + + //can't occupy the same cell as another char, so move back one. + if (Actor.findChar( cell ) != null && cell != curUser.pos) + cell = route.path.get(route.dist-1); + curUser.HP -= (curUser.HP / 3); if (curUser.subClass == HeroSubClass.BERSERKER && curUser.HP <= curUser.HT * Fury.LEVEL) { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java index bb6b8233c..fc22f8232 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/Wand.java @@ -70,7 +70,7 @@ public abstract class Wand extends KindOfWeapon { private int usagesToKnow = USAGES_TO_KNOW; - protected boolean hitChars = true; + protected int collisionProperties = Ballistica.MAGIC_BOLT; { @@ -125,7 +125,7 @@ public abstract class Wand extends KindOfWeapon { } } - protected abstract void onZap( int cell ); + protected abstract void onZap( Ballistica attack ); @Override public boolean collect( Bag container ) { @@ -260,8 +260,8 @@ public abstract class Wand extends KindOfWeapon { MAX = (tier * tier - tier + 10) / 2 + level; } - protected void fx( int cell, Callback callback ) { - MagicMissile.blueLight( curUser.sprite.parent, curUser.pos, cell, callback ); + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.blueLight( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } @@ -345,7 +345,8 @@ public abstract class Wand extends KindOfWeapon { final Wand curWand = (Wand)Wand.curItem; - final int cell = Ballistica.cast( curUser.pos, target, true, curWand.hitChars ); + final Ballistica shot = new Ballistica( curUser.pos, target, curWand.collisionProperties); + int cell = shot.collisionPos; if (target == curUser.pos || cell == curUser.pos) { GLog.i( TXT_SELF_TARGET ); @@ -354,17 +355,19 @@ public abstract class Wand extends KindOfWeapon { curUser.sprite.zap(cell); - //targets the enemy hit for char-hitting wands, or the cell aimed at for other wands. - QuickSlotButton.target(Actor.findChar(curWand.hitChars ? cell : target)); + //attempts to target the cell aimed at if something is there, otherwise targets the collision pos. + if (Actor.findChar(target) != null) + QuickSlotButton.target(Actor.findChar(target)); + else + QuickSlotButton.target(Actor.findChar(cell)); if (curWand.curCharges > 0) { curUser.busy(); - curWand.fx( cell, new Callback() { - @Override + curWand.fx( shot, new Callback() { public void call() { - curWand.onZap( cell ); + curWand.onZap( shot ); curWand.wandUsed(); } } ); diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAmok.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAmok.java index b84421c44..e0ab61dd4 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAmok.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAmok.java @@ -19,6 +19,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.watabou.noosa.audio.Sample; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; @@ -36,8 +37,8 @@ public class WandOfAmok extends Wand { } @Override - protected void onZap( int cell ) { - Char ch = Actor.findChar( cell ); + protected void onZap( Ballistica bolt) { + Char ch = Actor.findChar( bolt.collisionPos ); if (ch != null) { if (ch == Dungeon.hero) { @@ -52,9 +53,10 @@ public class WandOfAmok extends Wand { } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.purpleLight( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.purpleLight( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAvalanche.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAvalanche.java index e413641c4..31f824c95 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAvalanche.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfAvalanche.java @@ -42,20 +42,18 @@ public class WandOfAvalanche extends Wand { { name = "Wand of Avalanche"; - hitChars = false; + collisionProperties = Ballistica.STOP_TERRAIN; } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { Sample.INSTANCE.play( Assets.SND_ROCKS ); int level = level(); - Ballistica.distance = Math.min( Ballistica.distance, 8 + level ); - int size = 1 + level / 3; - PathFinder.buildDistanceMap( cell, BArray.not( Level.solid, null ), size ); + PathFinder.buildDistanceMap( bolt.collisionPos, BArray.not( Level.solid, null ), size ); for (int i=0; i < Level.LENGTH; i++) { @@ -85,9 +83,10 @@ public class WandOfAvalanche extends Wand { GLog.n( "You killed yourself with your own Wand of Avalanche..." ); } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.earth( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.earth( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfBlink.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfBlink.java index 46250a6e3..a6c5c716a 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfBlink.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfBlink.java @@ -35,24 +35,25 @@ public class WandOfBlink extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { int level = level(); - - if (Ballistica.distance > level + 4) { + + //TODO: don't care about this atm as this wand is marked for death, should correct this logic if I end up keeping it. + /*if (Ballistica.distance > level + 4) { cell = Ballistica.trace[level + 3]; } else if (Actor.findChar( cell ) != null && Ballistica.distance > 1) { cell = Ballistica.trace[Ballistica.distance - 2]; - } + }*/ curUser.sprite.visible = true; - appear( Dungeon.hero, cell ); + appear( Dungeon.hero, bolt.collisionPos ); Dungeon.observe(); } @Override - protected void fx( int cell, Callback callback ) { - MagicMissile.whiteLight( curUser.sprite.parent, curUser.pos, cell, callback ); + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.whiteLight( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); curUser.sprite.visible = false; } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfDisintegration.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfDisintegration.java index 1ec4d7020..4849e2fcf 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfDisintegration.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfDisintegration.java @@ -37,24 +37,21 @@ public class WandOfDisintegration extends Wand { { name = "Wand of Disintegration"; - hitChars = false; + collisionProperties = Ballistica.STOP_TERRAIN; } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica beam ) { boolean terrainAffected = false; int level = level(); - int maxDistance = distance(); - Ballistica.distance = Math.min( Ballistica.distance, maxDistance ); + int maxDistance = Math.min(distance(), beam.dist); ArrayList chars = new ArrayList(); - for (int i=1; i < Ballistica.distance; i++) { - - int c = Ballistica.trace[i]; + for (int c : beam.subPath(1, maxDistance)) { Char ch; if ((ch = Actor.findChar( c )) != null) { @@ -98,9 +95,9 @@ public class WandOfDisintegration extends Wand { } @Override - protected void fx( int cell, Callback callback ) { + protected void fx( Ballistica beam, Callback callback ) { - cell = Ballistica.trace[Math.min( Ballistica.distance, distance() ) - 1]; + int cell = beam.path.get(Math.min(beam.dist, distance())); curUser.sprite.parent.add( new DeathRay( curUser.sprite.center(), DungeonTilemap.tileCenterToWorld( cell ) ) ); callback.call(); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFirebolt.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFirebolt.java index e4fa2c054..6e7068d94 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFirebolt.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFirebolt.java @@ -44,17 +44,18 @@ public class WandOfFirebolt extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { int level = level(); - for (int i=1; i < Ballistica.distance - 1; i++) { - int c = Ballistica.trace[i]; + for (int c : bolt.subPath(0, bolt.dist)) { if (Level.flamable[c]) { GameScene.add( Blob.seed( c, 1, Fire.class ) ); } } - + + int cell = bolt.collisionPos; + GameScene.add( Blob.seed( cell, 1, Fire.class ) ); Char ch = Actor.findChar( cell ); @@ -71,9 +72,10 @@ public class WandOfFirebolt extends Wand { } } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.fire( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.fire( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFlock.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFlock.java index 500a08237..775ebb4df 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFlock.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfFlock.java @@ -42,15 +42,17 @@ public class WandOfFlock extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { int level = level(); int n = level + 2; - + + //TODO: don't care about this atm as this wand is marked for death, should correct this logic if I end up keeping it + /** if (Actor.findChar( cell ) != null && Ballistica.distance > 2) { cell = Ballistica.trace[Ballistica.distance - 2]; - } + }*/ boolean[] passable = BArray.or( Level.passable, Level.avoid, null ); for (Actor actor : Actor.all()) { @@ -58,6 +60,8 @@ public class WandOfFlock extends Wand { passable[((Char)actor).pos] = false; } } + + int cell = bolt.collisionPos; PathFinder.buildDistanceMap( cell, passable, n ); int dist = 0; diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java index a0da9a4cc..f6ebd07ee 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLightning.java @@ -20,6 +20,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands; import java.util.ArrayList; import java.util.HashSet; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.watabou.noosa.Camera; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions; @@ -47,7 +48,7 @@ public class WandOfLightning extends Wand { private int nPoints; @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { // Everything is processed in fx() method if (!curUser.isAlive()) { Dungeon.fail( Utils.format( ResultDescriptions.ITEM, name ) ); @@ -87,10 +88,12 @@ public class WandOfLightning extends Wand { } @Override - protected void fx( int cell, Callback callback ) { + protected void fx( Ballistica bolt, Callback callback ) { nPoints = 0; points[nPoints++] = Dungeon.hero.pos; + + int cell = bolt.collisionPos; Char ch = Actor.findChar( cell ); if (ch != null) { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfMagicMissile.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfMagicMissile.java index b695fc4c7..f721c530b 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfMagicMissile.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfMagicMissile.java @@ -26,6 +26,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; @@ -66,9 +67,9 @@ public class WandOfMagicMissile extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { - Char ch = Actor.findChar( cell ); + Char ch = Actor.findChar( bolt.collisionPos ); if (ch != null) { int level = level(); diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfPoison.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfPoison.java index 6806017f2..a8164fc5a 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfPoison.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfPoison.java @@ -17,6 +17,7 @@ */ package com.shatteredpixel.shatteredpixeldungeon.items.wands; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.watabou.noosa.audio.Sample; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; @@ -34,8 +35,8 @@ public class WandOfPoison extends Wand { } @Override - protected void onZap( int cell ) { - Char ch = Actor.findChar( cell ); + protected void onZap( Ballistica bolt ) { + Char ch = Actor.findChar( bolt.collisionPos ); if (ch != null) { Buff.affect( ch, Poison.class ).set( Poison.durationFactor( ch ) * (5 + level()) ); @@ -46,9 +47,10 @@ public class WandOfPoison extends Wand { } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.poison( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.poison( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java index 674938891..a14a9df2d 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfRegrowth.java @@ -37,28 +37,27 @@ public class WandOfRegrowth extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { - for (int i=1; i < Ballistica.distance-1; i++) { - int p = Ballistica.trace[i]; - int c = Dungeon.level.map[p]; + for (int i : bolt.subPath(1, bolt.dist)) { + int c = Dungeon.level.map[i]; if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO) { - Level.set( p, Terrain.GRASS ); + Level.set( i, Terrain.GRASS ); } } - int c = Dungeon.level.map[cell]; + int c = Dungeon.level.map[bolt.collisionPos]; if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO || c == Terrain.GRASS || c == Terrain.HIGH_GRASS) { - GameScene.add( Blob.seed( cell, (level() + 2) * 20, Regrowth.class ) ); + GameScene.add( Blob.seed( bolt.collisionPos, (level() + 2) * 20, Regrowth.class ) ); } else { @@ -66,9 +65,10 @@ public class WandOfRegrowth extends Wand { } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.foliage( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.foliage( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfSlowness.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfSlowness.java index 75f88af58..a8ead1508 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfSlowness.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfSlowness.java @@ -17,6 +17,7 @@ */ package com.shatteredpixel.shatteredpixeldungeon.items.wands; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.watabou.noosa.audio.Sample; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; @@ -34,8 +35,8 @@ public class WandOfSlowness extends Wand { } @Override - protected void onZap( int cell ) { - Char ch = Actor.findChar( cell ); + protected void onZap( Ballistica bolt) { + Char ch = Actor.findChar( bolt.collisionPos ); if (ch != null) { Buff.affect( ch, Slow.class, Slow.duration( ch ) / 3 + level() ); @@ -46,9 +47,10 @@ public class WandOfSlowness extends Wand { } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.slowness( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.slowness( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTelekinesis.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTelekinesis.java index 822ce957f..1f10fd763 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTelekinesis.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTelekinesis.java @@ -17,25 +17,17 @@ */ package com.shatteredpixel.shatteredpixeldungeon.items.wands; -import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Shopkeeper; import com.watabou.noosa.audio.Sample; 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.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; -import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop; import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Heap.Type; import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade; -import com.shatteredpixel.shatteredpixeldungeon.levels.Level; -import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; -import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; import com.watabou.utils.Callback; @@ -45,12 +37,14 @@ public class WandOfTelekinesis extends Wand { { name = "Wand of Telekinesis"; - hitChars = false; + collisionProperties = Ballistica.STOP_TERRAIN; } @Override - protected void onZap( int cell ) { - + protected void onZap( Ballistica bolt ) { + + //TODO: this whole wand is getting reworked anyway, so screw trying to correct this logic, just rewrite. + /* boolean mapUpdated = false; int maxDistance = level() + 4; @@ -131,6 +125,7 @@ public class WandOfTelekinesis extends Wand { if (mapUpdated) { Dungeon.observe(); } + */ } private void transport( Heap heap ) { @@ -159,9 +154,10 @@ public class WandOfTelekinesis extends Wand { heap.sprite.link(); heap.sprite.drop(); } - - protected void fx( int cell, Callback callback ) { - MagicMissile.force( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.force( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTeleportation.java b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTeleportation.java index 884cb4ac7..6c52c6629 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTeleportation.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfTeleportation.java @@ -18,6 +18,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.wands; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.watabou.noosa.audio.Sample; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; @@ -35,9 +36,9 @@ public class WandOfTeleportation extends Wand { } @Override - protected void onZap( int cell ) { + protected void onZap( Ballistica bolt ) { - Char ch = Actor.findChar( cell ); + Char ch = Actor.findChar( bolt.collisionPos ); if (ch == curUser) { @@ -73,9 +74,10 @@ public class WandOfTeleportation extends Wand { } } - - protected void fx( int cell, Callback callback ) { - MagicMissile.coldLight( curUser.sprite.parent, curUser.pos, cell, callback ); + + @Override + protected void fx( Ballistica bolt, Callback callback ) { + MagicMissile.coldLight( curUser.sprite.parent, bolt.sourcePos, bolt.collisionPos, callback ); Sample.INSTANCE.play( Assets.SND_ZAP ); } diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java b/src/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java index 38c1ab050..b0423f2ee 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java @@ -100,8 +100,7 @@ public abstract class Level implements Bundlable { public static final int[] NEIGHBOURS8 = {+1, -1, +WIDTH, -WIDTH, +1+WIDTH, +1-WIDTH, -1+WIDTH, -1-WIDTH}; public static final int[] NEIGHBOURS9 = {0, +1, -1, +WIDTH, -WIDTH, +1+WIDTH, +1-WIDTH, -1+WIDTH, -1-WIDTH}; - //Note that use of these without checking values is unsafe, mobs can be within 2 tiles of the - //edge of the map, unsafe use in that cause will cause an array out of bounds exception. + //make sure to check insideMap() when using these, as there's a risk something may be outside the map public static final int[] NEIGHBOURS8DIST2 = {+2+2*WIDTH, +1+2*WIDTH, 2*WIDTH, -1+2*WIDTH, -2+2*WIDTH, +2+WIDTH, +1+WIDTH, +WIDTH, -1+WIDTH, -2+WIDTH, +2, +1, -1, -2, @@ -971,6 +970,16 @@ public abstract class Level implements Bundlable { int diff = Math.abs( a - b ); return diff == 1 || diff == WIDTH || diff == WIDTH + 1 || diff == WIDTH - 1; } + + //returns true if the input is a valid tile within the level + public static boolean insideMap( int tile ){ + //outside map array + return !((tile <= -1 || tile >= LENGTH) || + //top and bottom row + (tile <= 31 || tile >= LENGTH - WIDTH) || + //left and right column + (tile % WIDTH == 0 || tile % WIDTH == 31)); + } public String tileName( int tile ) { diff --git a/src/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java b/src/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java index aed223f38..26d233b74 100644 --- a/src/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java +++ b/src/com/shatteredpixel/shatteredpixeldungeon/mechanics/Ballistica.java @@ -1,6 +1,9 @@ /* * Pixel Dungeon - * Copyright (C) 2012-2014 Oleg Dolya + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2015 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 @@ -20,43 +23,73 @@ package com.shatteredpixel.shatteredpixeldungeon.mechanics; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; +import java.util.ArrayList; +import java.util.List; + public class Ballistica { - public static int[] trace = new int[Math.max( Level.WIDTH, Level.HEIGHT )]; - public static int distance; + //note that the path is the FULL path of the projectile, including tiles after collision. + //make sure to generate a subPath for the common case of going source to collision. + public ArrayList path = new ArrayList<>(); + public Integer sourcePos = null; + public Integer collisionPos = null; + public Integer dist = 0; - public static int cast( int from, int to, boolean magic, boolean hitChars ) { - + //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 PROJECTILE = STOP_TARGET | STOP_CHARS | STOP_TERRAIN; + + //TODO: consider if we want thrown items to use this, or just have them all be projectileWeapons + public static final int THROWN_ITEM = STOP_TARGET | STOP_TERRAIN; + + public static final int MAGIC_BOLT = STOP_CHARS | STOP_TERRAIN; + + public static final int WONT_STOP = 0; + + + 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); + if (collisionPos != null) + dist = path.indexOf( collisionPos ); + else + collisionPos = path.get( dist=path.size()-1 ); + } + + private void build( int from, int to, boolean stopTarget, boolean stopChars, boolean stopTerrain ) { int w = Level.WIDTH; - + int x0 = from % w; int x1 = to % w; int y0 = from / w; int y1 = to / w; - + int dx = x1 - x0; int dy = y1 - y0; - + int stepX = dx > 0 ? +1 : -1; int stepY = dy > 0 ? +1 : -1; - + dx = Math.abs( dx ); dy = Math.abs( dy ); - + int stepA; int stepB; int dA; int dB; - + if (dx > dy) { - + stepA = stepX; stepB = stepY * w; dA = dx; dB = dy; } else { - + stepA = stepY * w; stepB = stepX; dA = dy; @@ -64,35 +97,48 @@ public class Ballistica { } - distance = 1; - trace[0] = from; - int cell = from; - + int err = dA / 2; - while (cell != to || magic) { - + while (Level.insideMap(cell)) { + + //if we're in a wall, collide with the previous cell along the path. + if (stopTerrain && !Level.passable[cell] && !Level.avoid[cell]) { + collide(path.get(path.size()-1)); + } + + path.add(cell); + + if ((stopTerrain && Level.losBlocking[cell]) + || (cell != sourcePos && stopChars && Actor.findChar( cell ) != null) + || (cell == to && stopTarget)){ + collide(cell); + } + cell += stepA; - + err += dB; if (err >= dA) { err = err - dA; cell = cell + stepB; } - - trace[distance++] = cell; - - if (!Level.passable[cell] && !Level.avoid[cell]) { - return trace[--distance - 1]; - } - - if (Level.losBlocking[cell] || (hitChars && Actor.findChar( cell ) != null)) { - return cell; - } } - - trace[distance++] = cell; - - return to; + } + + //we only want to record the first position collision occurs at. + private void collide(int cell){ + if (collisionPos == null) + collisionPos = cell; + } + + //returns a segment of the path from start to end, inclusive. + //if there is an error, returns an empty arraylist instead. + public List subPath(int start, int end){ + try { + end = Math.max( end, path.size()-1); + return path.subList(start, end+1); + } catch (Exception e){ + return new ArrayList<>(); + } } }