Disrupt weapons complete

This commit is contained in:
Anuken
2022-02-04 17:34:13 -05:00
parent 60621520ee
commit c8da241825
13 changed files with 171 additions and 69 deletions

View File

@@ -14,6 +14,8 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.defense.MendProjector.*;
import mindustry.world.blocks.defense.RegenProjector.*;
import static mindustry.Vars.*;
@@ -29,6 +31,34 @@ public class Damage{
private static Building tmpBuilding;
private static Unit tmpUnit;
private static IntFloatMap damages = new IntFloatMap();
private static Seq<Building> builds = new Seq<>();
public static void applySuppression(Team team, float x, float y, float range, float reload, float maxDelay, float applyParticleChance, @Nullable Position source){
builds.clear();
indexer.eachBlock(null, x, y, range, build -> build.team != team, build -> {
float prev = build.healSuppressionTime;
build.applyHealSuppression(reload + 1f);
//TODO maybe should be block field instead of instanceof check
if(build.wasRecentlyHealed(60f * 12f) || (build instanceof MendBuild || build instanceof RegenProjectorBuild)){
//add prev check so ability spam doesn't lead to particle spam (essentially, recently suppressed blocks don't get new particles)
if(!headless && prev - Time.time <= reload/2f){
builds.add(build);
}
}
});
//to prevent particle spam, the amount of particles is to remain constant (scales with number of buildings)
float scaledChance = applyParticleChance / builds.size;
for(var build : builds){
if(Mathf.chance(scaledChance)){
Time.run(Mathf.random(maxDelay), () -> {
Fx.regenSuppressSeek.at(build.x + Mathf.range(build.block.size * tilesize / 2f), build.y + Mathf.range(build.block.size * tilesize / 2f), 0f, source);
});
}
}
}
/** 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){

View File

@@ -3,26 +3,19 @@ package mindustry.entities.abilities;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.world.blocks.defense.MendProjector.*;
import mindustry.world.blocks.defense.RegenProjector.*;
import static mindustry.Vars.*;
public class SuppressionFieldAbility extends Ability{
protected static Rand rand = new Rand();
protected static Seq<Building> builds = new Seq<>();
public float reload = 60f * 1.5f;
public float range = 200f;
public float orbRadius = 4.1f, orbMidScl = 0.33f, orbSinScl = 8f, orbSinMag = 1f;
public Color color = Pal.sap.cpy().mul(1.6f);
public Color color = Pal.suppress;
public float layer = Layer.effect;
public float x = 0f, y = 0f;
@@ -37,49 +30,17 @@ public class SuppressionFieldAbility extends Ability{
public float applyParticleChance = 13f;
protected boolean any;
protected float timer;
protected float heat = 0f;
@Override
public void update(Unit unit){
if(!active) return;
if((timer += Time.delta) >= reload){
any = false;
builds.clear();
Vars.indexer.eachBlock(null, unit.x,unit.y, range, build -> true, build -> {
if(build.team != unit.team){
float prev = build.healSuppressionTime;
build.applyHealSuppression(reload + 1f);
//TODO maybe should be block field instead of instanceof check
if(build.wasRecentlyHealed(60f * 12f) || (build instanceof MendBuild || build instanceof RegenProjectorBuild)){
any = true;
//add prev check so ability spam doesn't lead to particle spam (essentially, recently suppressed blocks don't get new particles)
if(!headless && prev - Time.time <= reload/2f){
builds.add(build);
}
}
}
});
//to prevent particle spam, the amount of particles is to remain constant (scales with number of buildings)
float scaledChance = applyParticleChance / builds.size;
for(var build : builds){
if(Mathf.chance(scaledChance)){
Time.run(Mathf.random(reload), () -> {
Fx.regenSuppressSeek.at(build.x + Mathf.range(build.block.size * tilesize / 2f), build.y + Mathf.range(build.block.size * tilesize / 2f), 0f, unit);
});
}
}
Tmp.v1.set(x, y).rotate(unit.rotation - 90f).add(unit);
Damage.applySuppression(unit.team, Tmp.v1.x, Tmp.v1.y, range, reload, reload, applyParticleChance, unit);
timer = 0f;
}
heat = Mathf.lerpDelta(heat, any ? 1f : 0f, 0.09f);
}
@Override
@@ -87,8 +48,8 @@ public class SuppressionFieldAbility extends Ability{
Draw.z(layer);
float rad = orbRadius + Mathf.absin(orbSinScl, orbSinMag);
Tmp.v1.set(x, y).rotate(unit.rotation - 90f);
float rx = unit.x + Tmp.v1.x, ry = unit.y + Tmp.v1.y;
Tmp.v1.set(x, y).rotate(unit.rotation - 90f).add(unit);
float rx = Tmp.v1.x, ry = Tmp.v1.y;
float base = (Time.time / particleLife);
rand.setSeed(unit.id + hashCode());
@@ -112,13 +73,6 @@ public class SuppressionFieldAbility extends Ability{
Draw.color(color);
Fill.circle(rx, ry, rad * orbMidScl);
//TODO improve
if(heat > 0.001f && false){
Draw.color(Pal.sapBullet);
Lines.stroke(1.2f * heat * Mathf.absin(10f, 1f));
Lines.circle(rx, ry, range);
}
Draw.reset();
}
}

View File

@@ -5,6 +5,7 @@ import arc.audio.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
@@ -171,6 +172,8 @@ public class BulletType extends Content implements Cloneable{
/** Use a negative value to disable homing delay. */
public float homingDelay = -1f;
public float suppressionRange = -1f, suppressionDuration = 60f * 8f, suppressionEffectChance = 50f;
public Color lightningColor = Pal.surge;
public int lightning;
public int lightningLength = 5, lightningLengthRand = 0;
@@ -310,6 +313,11 @@ public class BulletType extends Content implements Cloneable{
Damage.createIncend(x, y, incendSpread, incendAmount);
}
if(suppressionRange > 0){
//bullets are pooled, require separate Vec2 instance
Damage.applySuppression(b.team, b.x, b.y, suppressionRange, suppressionDuration, 0f, suppressionEffectChance, new Vec2(b.x, b.y));
}
if(splashDamageRadius > 0 && !b.absorbed){
Damage.damage(b.team, x, y, splashDamageRadius, splashDamage * b.damageMultiplier(), false, collidesAir, collidesGround, scaledSplashDamage);

View File

@@ -19,7 +19,7 @@ public abstract class DrawPart{
/** Parameters for drawing a part in draw(). */
public static class PartParams{
//TODO document
public float warmup, reload, smoothReload, heat;
public float warmup, reload, smoothReload, heat, life;
public float x, y, rotation;
public int sideOverride = -1;
@@ -32,6 +32,7 @@ public abstract class DrawPart{
this.y = y;
this.rotation = rotation;
this.sideOverride = -1;
this.life = 0f;
return this;
}
}
@@ -45,7 +46,9 @@ public abstract class DrawPart{
/** Weapon warmup, 0 when not firing, 1 when actively shooting. Not equivalent to heat. */
warmup = p -> p.warmup,
/** Weapon heat, 1 when just fired, 0, when it has cooled down (duration depends on weapon) */
heat = p -> p.heat;
heat = p -> p.heat,
/** Lifetime fraction, 0 to 1. Only for missiles. */
life = p -> p.life;
float get(PartParams p);
@@ -78,7 +81,7 @@ public abstract class DrawPart{
}
default PartProgress mul(float amount){
return p -> get(p) * amount;
return p -> Mathf.clamp(get(p) * amount);
}
default PartProgress min(PartProgress other){

View File

@@ -3,7 +3,6 @@ package mindustry.entities.part;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.graphics.*;
@@ -30,7 +29,6 @@ public class RegionPart extends DrawPart{
/** Progress function for heat alpha. */
public PartProgress heatProgress = PartProgress.heat;
public Blending blending = Blending.normal;
public Interp interp = Interp.linear;
public float layer = -1, layerOffset = 0f;
public float outlineLayerOffset = -0.001f;
public float rotation, rotMove;
@@ -64,7 +62,6 @@ public class RegionPart extends DrawPart{
float prevZ = Draw.z();
float prog = progress.get(params);
prog = interp.apply(prog);
int len = mirror && params.sideOverride == -1 ? 2 : 1;
for(int s = 0; s < len; s++){

View File

@@ -0,0 +1,64 @@
package mindustry.entities.part;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
public class ShapePart extends DrawPart{
public boolean circle = false;
public int sides = 3;
public float radius = 3f, radiusTo = -1f;
public float x, y, rotation;
public float moveX, moveY, rotMove;
public Color color = Color.white;
public @Nullable Color colorTo;
public boolean mirror = false;
public PartProgress progress = PartProgress.warmup;
public float layer = -1f, layerOffset = 0f;
@Override
public void draw(PartParams params){
float z = Draw.z();
if(layer > 0) Draw.z(layer);
if(under && turretShading) Draw.z(z - 0.0001f);
Draw.z(Draw.z() + layerOffset);
float prog = progress.get(params);
int len = mirror && params.sideOverride == -1 ? 2 : 1;
for(int s = 0; s < len; s++){
//use specific side if necessary
int i = params.sideOverride == -1 ? s : params.sideOverride;
float sign = i == 1 ? -1 : 1;
Tmp.v1.set((x + moveX * prog) * sign, y + moveY * prog).rotate(params.rotation - 90);
float
rx = params.x + Tmp.v1.x,
ry = params.y + Tmp.v1.y,
rad = radiusTo < 0 ? radius : Mathf.lerp(radius, radiusTo, prog);
if(color != null && colorTo != null){
Draw.color(color, colorTo, prog);
}else if(color != null){
Draw.color(color);
}
if(!circle){
Fill.poly(rx, ry, sides, rad, rotMove * prog * sign + params.rotation - 90);
}else{
Fill.circle(rx, ry, rad);
}
if(color != null) Draw.color();
}
Draw.z(z);
}
@Override
public void load(String name){
}
}