v0.9.0: adjusted ballisticas and webs:

- webs and doors are now 'soft solid' terrain (solid, but can be stepped through)
- ballisticas can now ignore soft solid terrain, instead of just doors
- webs are now flammable
This commit is contained in:
Evan Debenham 2020-09-13 16:40:32 -04:00
parent 1d36642068
commit 61268df037
11 changed files with 35 additions and 25 deletions

View File

@ -52,6 +52,7 @@ public class Web extends Blob {
volume += off[cell]; volume += off[cell];
l.solid[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0; l.solid[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0;
l.flamable[cell] = off[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.FLAMABLE) != 0;
} }
} }
} }
@ -60,6 +61,7 @@ public class Web extends Blob {
public void seed(Level level, int cell, int amount) { public void seed(Level level, int cell, int amount) {
super.seed(level, cell, amount); super.seed(level, cell, amount);
level.solid[cell] = cur[cell] > 0 || (Terrain.flags[level.map[cell]] & Terrain.SOLID) != 0; level.solid[cell] = cur[cell] > 0 || (Terrain.flags[level.map[cell]] & Terrain.SOLID) != 0;
level.flamable[cell] = cur[cell] > 0 || (Terrain.flags[level.map[cell]] & Terrain.FLAMABLE) != 0;
} }
//affects characters as they step on it. See Level.OccupyCell and Level.PressCell //affects characters as they step on it. See Level.OccupyCell and Level.PressCell
@ -80,6 +82,7 @@ public class Web extends Blob {
if (cur == null) return; if (cur == null) return;
Level l = Dungeon.level; Level l = Dungeon.level;
l.solid[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0; l.solid[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.SOLID) != 0;
l.flamable[cell] = cur[cell] > 0 || (Terrain.flags[l.map[cell]] & Terrain.FLAMABLE) != 0;
} }
@Override @Override

View File

@ -86,7 +86,7 @@ public class Eye extends Mob {
protected boolean canAttack( Char enemy ) { protected boolean canAttack( Char enemy ) {
if (beamCooldown == 0) { if (beamCooldown == 0) {
Ballistica aim = new Ballistica(pos, enemy.pos, Ballistica.STOP_TERRAIN); Ballistica aim = new Ballistica(pos, enemy.pos, Ballistica.STOP_SOLID);
if (enemy.invisible == 0 && !isCharmedBy(enemy) && fieldOfView[enemy.pos] && aim.subPath(1, aim.dist).contains(enemy.pos)){ if (enemy.invisible == 0 && !isCharmedBy(enemy) && fieldOfView[enemy.pos] && aim.subPath(1, aim.dist).contains(enemy.pos)){
beam = aim; beam = aim;
@ -106,7 +106,7 @@ public class Eye extends Mob {
sprite.idle(); sprite.idle();
} }
if (beam == null && beamTarget != -1) { if (beam == null && beamTarget != -1) {
beam = new Ballistica(pos, beamTarget, Ballistica.STOP_TERRAIN); beam = new Ballistica(pos, beamTarget, Ballistica.STOP_SOLID);
sprite.turnTo(pos, beamTarget); sprite.turnTo(pos, beamTarget);
} }
if (beamCooldown > 0) if (beamCooldown > 0)
@ -128,7 +128,7 @@ public class Eye extends Mob {
spend( attackDelay() ); spend( attackDelay() );
beam = new Ballistica(pos, beamTarget, Ballistica.STOP_TERRAIN); beam = new Ballistica(pos, beamTarget, Ballistica.STOP_SOLID);
if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[beam.collisionPos] ) { if (Dungeon.level.heroFOV[pos] || Dungeon.level.heroFOV[beam.collisionPos] ) {
sprite.zap( beam.collisionPos ); sprite.zap( beam.collisionPos );
return false; return false;

View File

@ -205,11 +205,11 @@ public class RipperDemon extends Mob {
targetPos = enemy.pos + PathFinder.CIRCLE8[(closestIdx+4)%8]; targetPos = enemy.pos + PathFinder.CIRCLE8[(closestIdx+4)%8];
} }
Ballistica b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_TERRAIN); Ballistica b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID);
//try aiming directly at hero if aiming near them doesn't work //try aiming directly at hero if aiming near them doesn't work
if (b.collisionPos != targetPos && targetPos != enemy.pos){ if (b.collisionPos != targetPos && targetPos != enemy.pos){
targetPos = enemy.pos; targetPos = enemy.pos;
b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_TERRAIN); b = new Ballistica(pos, targetPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID);
} }
if (b.collisionPos == targetPos){ if (b.collisionPos == targetPos){
//get ready to leap //get ready to leap

View File

@ -171,7 +171,7 @@ public class Spinner extends Mob {
int webPos = b.path.get( collisionIndex+1 ); int webPos = b.path.get( collisionIndex+1 );
//ensure we aren't shooting the web through walls //ensure we aren't shooting the web through walls
int projectilePos = new Ballistica( pos, webPos, Ballistica.STOP_TARGET | Ballistica.STOP_TERRAIN).collisionPos; int projectilePos = new Ballistica( pos, webPos, Ballistica.STOP_TARGET | Ballistica.STOP_SOLID).collisionPos;
if (projectilePos == webPos && Dungeon.level.passable[webPos]){ if (projectilePos == webPos && Dungeon.level.passable[webPos]){
return webPos; return webPos;

View File

@ -82,12 +82,12 @@ public class PotionOfDragonsBreath extends ExoticPotion {
curUser.sprite.zap(cell); curUser.sprite.zap(cell);
Sample.INSTANCE.play( Assets.Sounds.BURNING ); Sample.INSTANCE.play( Assets.Sounds.BURNING );
final Ballistica bolt = new Ballistica(curUser.pos, cell, Ballistica.STOP_TERRAIN | Ballistica.IGNORE_DOORS); final Ballistica bolt = new Ballistica(curUser.pos, cell, Ballistica.STOP_SOLID | Ballistica.IGNORE_SOFT_SOLID);
int maxDist = 6; int maxDist = 6;
int dist = Math.min(bolt.dist, maxDist); int dist = Math.min(bolt.dist, maxDist);
final ConeAOE cone = new ConeAOE(bolt, 6, 60, Ballistica.STOP_TERRAIN | Ballistica.STOP_TARGET | Ballistica.IGNORE_DOORS ); final ConeAOE cone = new ConeAOE(bolt, 6, 60, Ballistica.STOP_SOLID | Ballistica.STOP_TARGET | Ballistica.IGNORE_SOFT_SOLID);
//cast to cells at the tip, rather than all cells, better performance. //cast to cells at the tip, rather than all cells, better performance.
for (Ballistica ray : cone.rays){ for (Ballistica ray : cone.rays){

View File

@ -48,7 +48,7 @@ public class WandOfCorrosion extends Wand {
{ {
image = ItemSpriteSheet.WAND_CORROSION; image = ItemSpriteSheet.WAND_CORROSION;
collisionProperties = Ballistica.STOP_TARGET | Ballistica.STOP_TERRAIN; collisionProperties = Ballistica.STOP_TARGET | Ballistica.STOP_SOLID;
} }
@Override @Override

View File

@ -85,7 +85,6 @@ public class WandOfDisintegration extends DamageWand {
if (Dungeon.level.solid[c]) { if (Dungeon.level.solid[c]) {
terrainPassed++; terrainPassed++;
if (web != null) web.clear(c);
} }
if (Dungeon.level.flamable[c]) { if (Dungeon.level.flamable[c]) {

View File

@ -52,7 +52,7 @@ public class WandOfFireblast extends DamageWand {
{ {
image = ItemSpriteSheet.WAND_FIREBOLT; image = ItemSpriteSheet.WAND_FIREBOLT;
collisionProperties = Ballistica.STOP_TERRAIN | Ballistica.IGNORE_DOORS; collisionProperties = Ballistica.STOP_SOLID | Ballistica.IGNORE_SOFT_SOLID;
} }
//1x/2x/3x damage //1x/2x/3x damage

View File

@ -58,7 +58,7 @@ public class WandOfRegrowth extends Wand {
{ {
image = ItemSpriteSheet.WAND_REGROWTH; image = ItemSpriteSheet.WAND_REGROWTH;
collisionProperties = Ballistica.STOP_TERRAIN; collisionProperties = Ballistica.STOP_SOLID;
} }
private int totChrgUsed = 0; private int totChrgUsed = 0;

View File

@ -635,6 +635,7 @@ public abstract class Level implements Bundlable {
if (w != null && w.volume > 0){ if (w != null && w.volume > 0){
for (int i=0; i < length(); i++) { for (int i=0; i < length(); i++) {
solid[i] = solid[i] || w.cur[i] > 0; solid[i] = solid[i] || w.cur[i] > 0;
flamable[i] = flamable[i] || w.cur[i] > 0;
} }
} }
@ -674,6 +675,10 @@ public abstract class Level implements Bundlable {
public void destroy( int pos ) { public void destroy( int pos ) {
set( pos, Terrain.EMBERS ); set( pos, Terrain.EMBERS );
Blob web = blobs.get(Web.class);
if (web != null){
web.clear(pos);
}
} }
public void cleanWalls() { public void cleanWalls() {

View File

@ -24,7 +24,6 @@ package com.shatteredpixel.shatteredpixeldungeon.mechanics;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -41,12 +40,12 @@ public class Ballistica {
//parameters to specify the colliding cell //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_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_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 STOP_SOLID = 4; //ballistica will stop on solid terrain
public static final int IGNORE_DOORS = 8; //ballistica will ignore doors instead of colliding public static final int IGNORE_SOFT_SOLID = 8; //ballistica will ignore soft solid terrain, such as doors and webs
public static final int PROJECTILE = STOP_TARGET | STOP_CHARS | STOP_TERRAIN; public static final int PROJECTILE = STOP_TARGET | STOP_CHARS | STOP_SOLID;
public static final int MAGIC_BOLT = STOP_CHARS | STOP_TERRAIN; public static final int MAGIC_BOLT = STOP_CHARS | STOP_SOLID;
public static final int WONT_STOP = 0; public static final int WONT_STOP = 0;
@ -56,8 +55,8 @@ public class Ballistica {
build(from, to, build(from, to,
(params & STOP_TARGET) > 0, (params & STOP_TARGET) > 0,
(params & STOP_CHARS) > 0, (params & STOP_CHARS) > 0,
(params & STOP_TERRAIN) > 0, (params & STOP_SOLID) > 0,
(params & IGNORE_DOORS) > 0); (params & IGNORE_SOFT_SOLID) > 0);
if (collisionPos != null) { if (collisionPos != null) {
dist = path.indexOf(collisionPos); dist = path.indexOf(collisionPos);
@ -70,7 +69,7 @@ public class Ballistica {
} }
} }
private void build( int from, int to, boolean stopTarget, boolean stopChars, boolean stopTerrain, boolean ignoreDoors ) { private void build( int from, int to, boolean stopTarget, boolean stopChars, boolean stopTerrain, boolean ignoreSoftSolid ) {
int w = Dungeon.level.width(); int w = Dungeon.level.width();
int x0 = from % w; int x0 = from % w;
@ -121,12 +120,16 @@ public class Ballistica {
path.add(cell); path.add(cell);
if ((stopTerrain && cell != sourcePos && Dungeon.level.solid[cell]) if (stopTerrain && cell != sourcePos && Dungeon.level.solid[cell]) {
|| (cell != sourcePos && stopChars && Actor.findChar( cell ) != null) if (ignoreSoftSolid && (Dungeon.level.passable[cell] || Dungeon.level.avoid[cell])) {
|| (cell == to && stopTarget)){ //do nothing
if (!ignoreDoors || Dungeon.level.map[cell] != Terrain.DOOR) { } else {
collide(cell); //only collide if this isn't a door, or we aren't ignoring doors collide(cell);
} }
} else if (cell != sourcePos && stopChars && Actor.findChar( cell ) != null) {
collide(cell);
} else if (cell == to && stopTarget){
collide(cell);
} }
cell += stepA; cell += stepA;