v0.3.0: reworked the ballistica system

This commit is contained in:
Evan Debenham 2015-03-26 22:43:23 -04:00
parent 9c1cfc095f
commit 99f853c190
27 changed files with 230 additions and 162 deletions

View File

@ -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;

View File

@ -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++;

View File

@ -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

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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 ) {

View File

@ -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

View File

@ -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 {

View File

@ -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();

View File

@ -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) {

View File

@ -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();
}
} );

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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<Char> chars = new ArrayList<Char>();
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();
}

View File

@ -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 );
}

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 ) {

View File

@ -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<Integer> 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<Integer> 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<>();
}
}
}