v0.8.1: wrote new logic for conical AOEs, and moved fireblast over to it
This commit is contained in:
parent
985b20ebff
commit
3fa4f6256f
|
@ -35,6 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Blazing;
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Blazing;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff;
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MagesStaff;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.ConeAOE;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
|
||||||
|
@ -63,28 +64,20 @@ public class WandOfFireblast extends DamageWand {
|
||||||
return (6+2*lvl) * chargesPerCast();
|
return (6+2*lvl) * chargesPerCast();
|
||||||
}
|
}
|
||||||
|
|
||||||
//the actual affected cells
|
ConeAOE cone;
|
||||||
private HashSet<Integer> affectedCells;
|
|
||||||
//the cells to trace fire shots to, for visual effects.
|
|
||||||
private HashSet<Integer> visualCells;
|
|
||||||
private int direction = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onZap( Ballistica bolt ) {
|
protected void onZap( Ballistica bolt ) {
|
||||||
|
|
||||||
ArrayList<Char> affectedChars = new ArrayList<>();
|
ArrayList<Char> affectedChars = new ArrayList<>();
|
||||||
for( int cell : affectedCells){
|
for( int cell : cone.cells ){
|
||||||
|
|
||||||
//ignore caster cell
|
//ignore caster cell
|
||||||
if (cell == bolt.sourcePos){
|
if (cell == bolt.sourcePos){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//only ignite cells directly near caster if they are flammable
|
|
||||||
if (!Dungeon.level.adjacent(bolt.sourcePos, cell)
|
|
||||||
|| Dungeon.level.flamable[cell]){
|
|
||||||
GameScene.add( Blob.seed( cell, 1+chargesPerCast(), Fire.class ) );
|
GameScene.add( Blob.seed( cell, 1+chargesPerCast(), Fire.class ) );
|
||||||
}
|
|
||||||
|
|
||||||
Char ch = Actor.findChar( cell );
|
Char ch = Actor.findChar( cell );
|
||||||
if (ch != null) {
|
if (ch != null) {
|
||||||
|
@ -107,30 +100,6 @@ public class WandOfFireblast extends DamageWand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//burn... BURNNNNN!.....
|
|
||||||
private void spreadFlames(int cell, float strength){
|
|
||||||
if (strength >= 0 && (Dungeon.level.passable[cell] || Dungeon.level.flamable[cell])){
|
|
||||||
affectedCells.add(cell);
|
|
||||||
if (strength >= 1.5f) {
|
|
||||||
visualCells.remove(cell);
|
|
||||||
spreadFlames(cell + PathFinder.CIRCLE8[left(direction)], strength - 1.5f);
|
|
||||||
spreadFlames(cell + PathFinder.CIRCLE8[direction], strength - 1.5f);
|
|
||||||
spreadFlames(cell + PathFinder.CIRCLE8[right(direction)], strength - 1.5f);
|
|
||||||
} else {
|
|
||||||
visualCells.add(cell);
|
|
||||||
}
|
|
||||||
} else if (!Dungeon.level.passable[cell])
|
|
||||||
visualCells.add(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int left(int direction){
|
|
||||||
return direction == 0 ? 7 : direction-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int right(int direction){
|
|
||||||
return direction == 7 ? 0 : direction+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHit(MagesStaff staff, Char attacker, Char defender, int damage) {
|
public void onHit(MagesStaff staff, Char attacker, Char defender, int damage) {
|
||||||
//acts like blazing enchantment
|
//acts like blazing enchantment
|
||||||
|
@ -140,45 +109,27 @@ public class WandOfFireblast extends DamageWand {
|
||||||
@Override
|
@Override
|
||||||
protected void fx( Ballistica bolt, Callback callback ) {
|
protected void fx( Ballistica bolt, Callback callback ) {
|
||||||
//need to perform flame spread logic here so we can determine what cells to put flames in.
|
//need to perform flame spread logic here so we can determine what cells to put flames in.
|
||||||
affectedCells = new HashSet<>();
|
|
||||||
visualCells = new HashSet<>();
|
|
||||||
|
|
||||||
// 4/6/8 distance
|
// 4/6/8 distance
|
||||||
int maxDist = 2 + 2*chargesPerCast();
|
int maxDist = 2 + 2*chargesPerCast();
|
||||||
int dist = Math.min(bolt.dist, maxDist);
|
int dist = Math.min(bolt.dist, maxDist);
|
||||||
|
|
||||||
for (int i = 0; i < PathFinder.CIRCLE8.length; i++){
|
cone = new ConeAOE( bolt.sourcePos, bolt.path.get(dist),
|
||||||
if (bolt.sourcePos+PathFinder.CIRCLE8[i] == bolt.path.get(1)){
|
maxDist,
|
||||||
direction = i;
|
30 + 20*chargesPerCast(),
|
||||||
break;
|
collisionProperties | Ballistica.STOP_TARGET);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float strength = maxDist;
|
//cast to cells at the tip, rather than all cells, better performance.
|
||||||
for (int c : bolt.subPath(1, dist)) {
|
for (Ballistica ray : cone.rays){
|
||||||
strength--; //as we start at dist 1, not 0.
|
|
||||||
affectedCells.add(c);
|
|
||||||
if (strength > 1) {
|
|
||||||
spreadFlames(c + PathFinder.CIRCLE8[left(direction)], strength - 1);
|
|
||||||
spreadFlames(c + PathFinder.CIRCLE8[direction], strength - 1);
|
|
||||||
spreadFlames(c + PathFinder.CIRCLE8[right(direction)], strength - 1);
|
|
||||||
} else {
|
|
||||||
visualCells.add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//going to call this one manually
|
|
||||||
visualCells.remove(bolt.path.get(dist));
|
|
||||||
|
|
||||||
for (int cell : visualCells){
|
|
||||||
//this way we only get the cells at the tip, much better performance.
|
|
||||||
((MagicMissile)curUser.sprite.parent.recycle( MagicMissile.class )).reset(
|
((MagicMissile)curUser.sprite.parent.recycle( MagicMissile.class )).reset(
|
||||||
MagicMissile.FIRE_CONE,
|
MagicMissile.FIRE_CONE,
|
||||||
curUser.sprite,
|
curUser.sprite,
|
||||||
cell,
|
ray.path.get(ray.dist),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//final zap at half distance, for timing of the actual wand effect
|
||||||
MagicMissile.boltFromChar( curUser.sprite.parent,
|
MagicMissile.boltFromChar( curUser.sprite.parent,
|
||||||
MagicMissile.FIRE_CONE,
|
MagicMissile.FIRE_CONE,
|
||||||
curUser.sprite,
|
curUser.sprite,
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2020 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.mechanics;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||||
|
import com.watabou.utils.GameMath;
|
||||||
|
import com.watabou.utils.Point;
|
||||||
|
import com.watabou.utils.PointF;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
|
//a cone made of up several ballisticas scanning in an arc
|
||||||
|
public class ConeAOE {
|
||||||
|
|
||||||
|
public ArrayList<Ballistica> rays = new ArrayList<>();
|
||||||
|
public HashSet<Integer> cells = new HashSet<>();
|
||||||
|
|
||||||
|
public ConeAOE( int from, int to, float degrees ){
|
||||||
|
this(from, to, Float.POSITIVE_INFINITY, degrees, Ballistica.STOP_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConeAOE( int from, int to, float maxDist, float degrees, int ballisticaParams ){
|
||||||
|
|
||||||
|
//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));
|
||||||
|
fromP.x += 0.5f;
|
||||||
|
fromP.y += 0.5f;
|
||||||
|
PointF toP = new PointF(Dungeon.level.cellToPoint(to));
|
||||||
|
toP.x += 0.5f;
|
||||||
|
toP.y += 0.5f;
|
||||||
|
|
||||||
|
//clamp distance of cone to maxDist (in true distance, not game distance)
|
||||||
|
if (PointF.distance(fromP, toP) > maxDist){
|
||||||
|
toP = PointF.inter(fromP, toP, maxDist/PointF.distance(fromP, toP) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//now we can get the circle's radius. We bump it by 0.5 as we want the cone to reach
|
||||||
|
// The edge of the target cell, not the center.
|
||||||
|
float circleRadius = PointF.distance(fromP, toP);
|
||||||
|
circleRadius += 0.5f;
|
||||||
|
|
||||||
|
//Now we find every unique cell along the outer arc of our cone.
|
||||||
|
PointF scan = new PointF();
|
||||||
|
Point scanInt = new Point();
|
||||||
|
float initalAngle = PointF.angle(fromP, toP)/PointF.G2R;
|
||||||
|
//want to preserve order so that our collection of rays is going clockwise
|
||||||
|
LinkedHashSet<Integer> targetCells = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
//cast a ray every 0.5 degrees in a clockwise arc, to find cells along the cone's outer arc
|
||||||
|
for (float a = initalAngle+degrees/2f; a >= initalAngle-degrees/2f; a-=0.5f){
|
||||||
|
scan.polar(a * PointF.G2R, circleRadius);
|
||||||
|
scan.offset(fromP);
|
||||||
|
scan.x += (fromP.x > scan.x ? +0.5f : -0.5f);
|
||||||
|
scan.y += (fromP.y > scan.y ? +0.5f : -0.5f);
|
||||||
|
scanInt.set(
|
||||||
|
(int)GameMath.gate(0, (int)Math.floor(scan.x), Dungeon.level.width()-1),
|
||||||
|
(int)GameMath.gate(0, (int)Math.floor(scan.y), Dungeon.level.height()-1));
|
||||||
|
targetCells.add(Dungeon.level.pointToCell(scanInt));
|
||||||
|
//if the cone is large enough, also cast rays to cells just inside of the outer arc
|
||||||
|
// this helps fill in any holes when casting rays
|
||||||
|
if (circleRadius >= 7) {
|
||||||
|
scan.polar(a * PointF.G2R, circleRadius - 1);
|
||||||
|
scan.offset(fromP);
|
||||||
|
scan.x += (fromP.x > scan.x ? +0.5f : -0.5f);
|
||||||
|
scan.y += (fromP.y > scan.y ? +0.5f : -0.5f);
|
||||||
|
scanInt.set(
|
||||||
|
(int)GameMath.gate(0, (int)Math.floor(scan.x), Dungeon.level.width()-1),
|
||||||
|
(int)GameMath.gate(0, (int)Math.floor(scan.y), Dungeon.level.height()-1));
|
||||||
|
targetCells.add(Dungeon.level.pointToCell(scanInt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cast a ray to each found cell, these make up the cone
|
||||||
|
for( int c : targetCells ){
|
||||||
|
Ballistica ray = new Ballistica(from, c, ballisticaParams);
|
||||||
|
cells.addAll(ray.subPath(1, ray.dist));
|
||||||
|
rays.add(ray);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user