New splash damage algorithm
This commit is contained in:
@@ -1609,6 +1609,12 @@ public class Fx{
|
|||||||
Fill.square(e.x, e.y, e.rotation * tilesize / 2f);
|
Fill.square(e.x, e.y, e.rotation * tilesize / 2f);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
lightBlock = new Effect(60, e -> {
|
||||||
|
color(e.color);
|
||||||
|
alpha(e.fout() * 1);
|
||||||
|
Fill.square(e.x, e.y, e.rotation * tilesize / 2f);
|
||||||
|
}),
|
||||||
|
|
||||||
overdriveBlockFull = new Effect(60, e -> {
|
overdriveBlockFull = new Effect(60, e -> {
|
||||||
color(e.color);
|
color(e.color);
|
||||||
alpha(e.fslope() * 0.4f);
|
alpha(e.fslope() * 0.4f);
|
||||||
|
|||||||
@@ -565,9 +565,9 @@ public class UnitTypes implements ContentList{
|
|||||||
hitEffect = Fx.pulverize;
|
hitEffect = Fx.pulverize;
|
||||||
lifetime = 10f;
|
lifetime = 10f;
|
||||||
speed = 1f;
|
speed = 1f;
|
||||||
splashDamageRadius = 70f;
|
splashDamageRadius = 58f;
|
||||||
instantDisappear = true;
|
instantDisappear = true;
|
||||||
splashDamage = 80f;
|
splashDamage = 85f;
|
||||||
killShooter = true;
|
killShooter = true;
|
||||||
hittable = false;
|
hittable = false;
|
||||||
collidesAir = true;
|
collidesAir = true;
|
||||||
@@ -769,7 +769,7 @@ public class UnitTypes implements ContentList{
|
|||||||
width = height = 19f;
|
width = height = 19f;
|
||||||
collidesTiles = true;
|
collidesTiles = true;
|
||||||
ammoMultiplier = 4f;
|
ammoMultiplier = 4f;
|
||||||
splashDamageRadius = 95f;
|
splashDamageRadius = 80f;
|
||||||
splashDamage = 65f;
|
splashDamage = 65f;
|
||||||
backColor = Pal.sapBulletBack;
|
backColor = Pal.sapBulletBack;
|
||||||
frontColor = lightningColor = Pal.sapBullet;
|
frontColor = lightningColor = Pal.sapBullet;
|
||||||
@@ -867,7 +867,7 @@ public class UnitTypes implements ContentList{
|
|||||||
width = height = 25f;
|
width = height = 25f;
|
||||||
collidesTiles = collides = true;
|
collidesTiles = collides = true;
|
||||||
ammoMultiplier = 4f;
|
ammoMultiplier = 4f;
|
||||||
splashDamageRadius = 90f;
|
splashDamageRadius = 80f;
|
||||||
splashDamage = 75f;
|
splashDamage = 75f;
|
||||||
backColor = Pal.sapBulletBack;
|
backColor = Pal.sapBulletBack;
|
||||||
frontColor = lightningColor = Pal.sapBullet;
|
frontColor = lightningColor = Pal.sapBullet;
|
||||||
@@ -888,7 +888,7 @@ public class UnitTypes implements ContentList{
|
|||||||
lifetime = 90f;
|
lifetime = 90f;
|
||||||
width = height = 20f;
|
width = height = 20f;
|
||||||
collidesTiles = false;
|
collidesTiles = false;
|
||||||
splashDamageRadius = 80f;
|
splashDamageRadius = 70f;
|
||||||
splashDamage = 40f;
|
splashDamage = 40f;
|
||||||
backColor = Pal.sapBulletBack;
|
backColor = Pal.sapBulletBack;
|
||||||
frontColor = lightningColor = Pal.sapBullet;
|
frontColor = lightningColor = Pal.sapBullet;
|
||||||
@@ -1367,7 +1367,7 @@ public class UnitTypes implements ContentList{
|
|||||||
|
|
||||||
healPercent = 15f;
|
healPercent = 15f;
|
||||||
splashDamage = 230f;
|
splashDamage = 230f;
|
||||||
splashDamageRadius = 120f;
|
splashDamageRadius = 81f;
|
||||||
}};
|
}};
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
@@ -1537,7 +1537,7 @@ public class UnitTypes implements ContentList{
|
|||||||
width = 15f;
|
width = 15f;
|
||||||
collidesTiles = false;
|
collidesTiles = false;
|
||||||
ammoMultiplier = 4f;
|
ammoMultiplier = 4f;
|
||||||
splashDamageRadius = 60f;
|
splashDamageRadius = 50f;
|
||||||
splashDamage = 80f;
|
splashDamage = 80f;
|
||||||
backColor = Pal.missileYellowBack;
|
backColor = Pal.missileYellowBack;
|
||||||
frontColor = Pal.missileYellow;
|
frontColor = Pal.missileYellow;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import arc.math.*;
|
|||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.core.*;
|
import mindustry.core.*;
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
@@ -25,11 +24,10 @@ public class Damage{
|
|||||||
private static Rect hitrect = new Rect();
|
private static Rect hitrect = new Rect();
|
||||||
private static Vec2 tr = new Vec2(), seg1 = new Vec2(), seg2 = new Vec2();
|
private static Vec2 tr = new Vec2(), seg1 = new Vec2(), seg2 = new Vec2();
|
||||||
private static Seq<Unit> units = new Seq<>();
|
private static Seq<Unit> units = new Seq<>();
|
||||||
private static GridBits bits = new GridBits(30, 30);
|
|
||||||
private static IntQueue propagation = new IntQueue();
|
|
||||||
private static IntSet collidedBlocks = new IntSet();
|
private static IntSet collidedBlocks = new IntSet();
|
||||||
private static Building tmpBuilding;
|
private static Building tmpBuilding;
|
||||||
private static Unit tmpUnit;
|
private static Unit tmpUnit;
|
||||||
|
private static IntFloatMap damages = new IntFloatMap();
|
||||||
|
|
||||||
/** Creates a dynamic explosion based on specified parameters. */
|
/** Creates a dynamic explosion based on specified parameters. */
|
||||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage){
|
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage){
|
||||||
@@ -365,64 +363,85 @@ public class Damage{
|
|||||||
|
|
||||||
if(ground){
|
if(ground){
|
||||||
if(!complete){
|
if(!complete){
|
||||||
int trad = (int)(radius / tilesize);
|
//increase damage slightly to compensate for new algorithm
|
||||||
Tile tile = world.tileWorld(x, y);
|
tileDamage(team, World.toTile(x), World.toTile(y), radius / tilesize, damage * 1.1f);
|
||||||
if(tile != null){
|
|
||||||
tileDamage(team, tile.x, tile.y, trad, damage);
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
completeDamage(team, x, y, radius, damage);
|
completeDamage(team, x, y, radius, damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tileDamage(Team team, int startx, int starty, int baseRadius, float baseDamage){
|
public static void tileDamage(Team team, int x, int y, float baseRadius, float damage){
|
||||||
//tile damage is posted, so that destroying a block that causes a chain explosion will run in the next frame
|
|
||||||
//this prevents recursive damage calls from messing up temporary variables
|
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
|
|
||||||
bits.clear();
|
var in = world.build(x, y);
|
||||||
propagation.clear();
|
//spawned inside a multiblock. this means that damage needs to be dealt directly.
|
||||||
int bitOffset = bits.width() / 2;
|
//why? because otherwise the building would absorb everything in one cell, which means much less damage than a nearby explosion.
|
||||||
|
//this needs to be compensated
|
||||||
|
if(in != null && in.team != team && in.block.size > 1 && in.health > damage){
|
||||||
|
//deal the damage of an entire side * 2, to be equivalent with the maximum "standard" side damage + 1
|
||||||
|
in.damage(damage * (in.block.size * 2));
|
||||||
|
//no need to continue with the explosion
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
propagation.addFirst(PropCell.get((byte)0, (byte)0, (short)baseDamage));
|
//cap radius to prevent lag
|
||||||
//clamp radius to fit bits
|
float radius = Math.min(baseRadius, 30), rad2 = radius * radius;
|
||||||
int radius = Math.min(baseRadius, bits.width() / 2);
|
int rays = Mathf.ceil(radius * 2 * Mathf.pi);
|
||||||
|
double spacing = Math.PI * 2.0 / rays;
|
||||||
|
damages.clear();
|
||||||
|
|
||||||
while(!propagation.isEmpty()){
|
//raycast from each angle
|
||||||
int prop = propagation.removeLast();
|
for(int i = 0; i <= rays; i++){
|
||||||
int x = PropCell.x(prop);
|
float dealt = 0f;
|
||||||
int y = PropCell.y(prop);
|
int startX = x;
|
||||||
int damage = PropCell.damage(prop);
|
int startY = y;
|
||||||
//manhattan distance used for calculating falloff, results in a diamond pattern
|
int endX = x + (int)(Math.cos(spacing * i) * radius), endY = y + (int)(Math.sin(spacing * i) * radius);
|
||||||
int dst = Math.abs(x) + Math.abs(y);
|
|
||||||
|
|
||||||
int scaledDamage = (int)(damage * (1f - (float)dst / radius));
|
int xDist = Math.abs(endX - startX);
|
||||||
|
int yDist = -Math.abs(endY - startY);
|
||||||
|
int xStep = (startX < endX ? +1 : -1);
|
||||||
|
int yStep = (startY < endY ? +1 : -1);
|
||||||
|
int error = xDist + yDist;
|
||||||
|
|
||||||
bits.set(bitOffset + x, bitOffset + y);
|
while(startX != endX || startY != endY){
|
||||||
Tile tile = world.tile(startx + x, starty + y);
|
var build = world.build(startX, startY);
|
||||||
|
if(build != null && build.team != team){
|
||||||
|
//damage dealt at circle edge
|
||||||
|
float edgeScale = 0.6f;
|
||||||
|
float mult = (1f-(Mathf.dst2(startX, startY, x, y) / rad2) + edgeScale) / (1f + edgeScale);
|
||||||
|
float next = damage * mult - dealt;
|
||||||
|
//register damage dealt
|
||||||
|
int p = Point2.pack(startX, startY);
|
||||||
|
damages.put(p, Math.max(damages.get(p), next));
|
||||||
|
//register as hit
|
||||||
|
dealt += build.health;
|
||||||
|
|
||||||
if(scaledDamage <= 0 || tile == null) continue;
|
if(next - dealt <= 0){
|
||||||
|
break;
|
||||||
//apply damage to entity if needed
|
}
|
||||||
if(tile.build != null && tile.build.team != team){
|
|
||||||
int health = (int)(tile.build.health / (tile.block().size * tile.block().size));
|
|
||||||
if(tile.build.health > 0){
|
|
||||||
tile.build.damage(scaledDamage);
|
|
||||||
scaledDamage -= health;
|
|
||||||
|
|
||||||
if(scaledDamage <= 0) continue;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for(Point2 p : Geometry.d4){
|
if(2 * error - yDist > xDist - 2 * error){
|
||||||
if(!bits.get(bitOffset + x + p.x, bitOffset + y + p.y)){
|
error += yDist;
|
||||||
propagation.addFirst(PropCell.get((byte)(x + p.x), (byte)(y + p.y), (short)scaledDamage));
|
startX += xStep;
|
||||||
|
}else{
|
||||||
|
error += xDist;
|
||||||
|
startY += yStep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
//apply damage
|
||||||
|
for(var e : damages){
|
||||||
|
int cx = Point2.x(e.key), cy = Point2.y(e.key);
|
||||||
|
var build = world.build(cx, cy);
|
||||||
|
if(build != null){
|
||||||
|
build.damage(e.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void completeDamage(Team team, float x, float y, float radius, float damage){
|
private static void completeDamage(Team team, float x, float y, float radius, float damage){
|
||||||
@@ -443,11 +462,4 @@ public class Damage{
|
|||||||
float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff);
|
float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff);
|
||||||
return damage * scaled;
|
return damage * scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Struct
|
|
||||||
static class PropCellStruct{
|
|
||||||
byte x;
|
|
||||||
byte y;
|
|
||||||
short damage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import static mindustry.Vars.*;
|
|||||||
|
|
||||||
public class AIController implements UnitController{
|
public class AIController implements UnitController{
|
||||||
protected static final Vec2 vec = new Vec2();
|
protected static final Vec2 vec = new Vec2();
|
||||||
protected static final int timerTarget = 0, timerTarget2 = 1, timerTarget3 = 2, timerTarget4 = 2;
|
protected static final int timerTarget = 0, timerTarget2 = 1, timerTarget3 = 2, timerTarget4 = 3;
|
||||||
|
|
||||||
protected Unit unit;
|
protected Unit unit;
|
||||||
protected Interval timer = new Interval(4);
|
protected Interval timer = new Interval(4);
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ public class NuclearReactor extends PowerGenerator{
|
|||||||
public float itemDuration = 120; //time to consume 1 fuel
|
public float itemDuration = 120; //time to consume 1 fuel
|
||||||
public float heating = 0.01f; //heating per frame * fullness
|
public float heating = 0.01f; //heating per frame * fullness
|
||||||
public float smokeThreshold = 0.3f; //threshold at which block starts smoking
|
public float smokeThreshold = 0.3f; //threshold at which block starts smoking
|
||||||
public int explosionRadius = 40;
|
public int explosionRadius = 20;
|
||||||
public int explosionDamage = 1350;
|
public int explosionDamage = 1250;
|
||||||
public float flashThreshold = 0.46f; //heat threshold at which the lights start flashing
|
public float flashThreshold = 0.46f; //heat threshold at which the lights start flashing
|
||||||
public float coolantPower = 0.5f;
|
public float coolantPower = 0.5f;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user