Long-range 4x4 turret (wip) / Java 14 language upgrade
This commit is contained in:
@@ -74,7 +74,7 @@ public class Blocks implements ContentList{
|
||||
coreShard, coreFoundation, coreNucleus, vault, container, unloader,
|
||||
|
||||
//turrets
|
||||
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, segment, parallax,
|
||||
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax,
|
||||
|
||||
//units
|
||||
commandCenter,
|
||||
@@ -1665,6 +1665,48 @@ public class Blocks implements ContentList{
|
||||
health = 145 * size * size;
|
||||
}};
|
||||
|
||||
foreshadow = new ItemTurret("foreshadow"){{
|
||||
float brange = range = 500f;
|
||||
|
||||
requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgealloy, 300, Items.plastanium, 175, Items.thorium, 350));
|
||||
ammo(
|
||||
Items.surgealloy, new PointBulletType(){{
|
||||
shootEffect = Fx.instShoot;
|
||||
hitEffect = Fx.instHit;
|
||||
smokeEffect = Fx.smokeCloud;
|
||||
trailEffect = Fx.instTrail;
|
||||
despawnEffect = Fx.instBomb;
|
||||
trailSpacing = 20f;
|
||||
damage = 1300;
|
||||
tileDamageMultiplier = 0.5f;
|
||||
speed = brange;
|
||||
hitShake = 6f;
|
||||
ammoMultiplier = 1f;
|
||||
}}
|
||||
);
|
||||
|
||||
rotateSpeed = 2.5f;
|
||||
reloadTime = 200f;
|
||||
restitution = 0.2f;
|
||||
ammoUseEffect = Fx.shellEjectBig;
|
||||
recoilAmount = 5f;
|
||||
restitution = 0.009f;
|
||||
cooldown = 0.009f;
|
||||
shootShake = 4f;
|
||||
shots = 1;
|
||||
size = 4;
|
||||
shootCone = 2f;
|
||||
shootSound = Sounds.shootBig;
|
||||
unitSort = (u, x, y) -> -u.maxHealth;
|
||||
|
||||
coolantMultiplier = 0.09f;
|
||||
|
||||
health = 150 * size * size;
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true);
|
||||
|
||||
consumes.powerCond(10f, (TurretBuild entity) -> entity.target != null || (entity.logicControlled() && entity.logicShooting));
|
||||
}};
|
||||
|
||||
spectre = new ItemTurret("spectre"){{
|
||||
requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
|
||||
ammo(
|
||||
@@ -1687,7 +1729,7 @@ public class Blocks implements ContentList{
|
||||
shootCone = 24f;
|
||||
shootSound = Sounds.shootBig;
|
||||
|
||||
health = 155 * size * size;
|
||||
health = 160 * size * size;
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true);
|
||||
}};
|
||||
|
||||
|
||||
@@ -455,6 +455,79 @@ public class Fx{
|
||||
|
||||
}),
|
||||
|
||||
instBomb = new Effect(15f, 100f, e -> {
|
||||
color(Pal.bulletYellowBack);
|
||||
stroke(e.fout() * 4f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * 20f);
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
Drawf.tri(e.x, e.y, 6f, 80f * e.fout(), i*90 + 45);
|
||||
}
|
||||
|
||||
color();
|
||||
for(int i = 0; i < 4; i++){
|
||||
Drawf.tri(e.x, e.y, 3f, 30f * e.fout(), i*90 + 45);
|
||||
}
|
||||
}),
|
||||
|
||||
instTrail = new Effect(30, e -> {
|
||||
for(int i = 0; i < 2; i++){
|
||||
color(i == 0 ? Pal.bulletYellowBack : Pal.bulletYellow);
|
||||
|
||||
float m = i == 0 ? 1f : 0.5f;
|
||||
|
||||
float rot = e.rotation + 180f;
|
||||
float w = 15f * e.fout() * m;
|
||||
Drawf.tri(e.x, e.y, w, (30f + Mathf.randomSeedRange(e.id, 15f)) * m, rot);
|
||||
Drawf.tri(e.x, e.y, w, 10f * m, rot + 180f);
|
||||
}
|
||||
}),
|
||||
|
||||
instShoot = new Effect(24f, e -> {
|
||||
e.scaled(10f, b -> {
|
||||
color(Color.white, Pal.bulletYellowBack, b.fin());
|
||||
stroke(b.fout() * 3f + 0.2f);
|
||||
Lines.circle(b.x, b.y, b.fin() * 50f);
|
||||
});
|
||||
|
||||
color(Pal.bulletYellowBack);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 13f * e.fout(), 85f, e.rotation + 90f * i);
|
||||
Drawf.tri(e.x, e.y, 13f * e.fout(), 50f, e.rotation + 20f * i);
|
||||
}
|
||||
}),
|
||||
|
||||
instHit = new Effect(20f, 200f, e -> {
|
||||
color(Pal.bulletYellowBack);
|
||||
|
||||
for(int i = 0; i < 2; i++){
|
||||
color(i == 0 ? Pal.bulletYellowBack : Pal.bulletYellow);
|
||||
|
||||
float m = i == 0 ? 1f : 0.5f;
|
||||
|
||||
for(int j = 0; j < 5; j++){
|
||||
float rot = e.rotation + Mathf.randomSeedRange(e.id + j, 50f);
|
||||
float w = 23f * e.fout() * m;
|
||||
Drawf.tri(e.x, e.y, w, (80f + Mathf.randomSeedRange(e.id + j, 40f)) * m, rot);
|
||||
Drawf.tri(e.x, e.y, w, 20f * m, rot + 180f);
|
||||
}
|
||||
}
|
||||
|
||||
e.scaled(10f, c -> {
|
||||
color(Pal.bulletYellow);
|
||||
stroke(c.fout() * 2f + 0.2f);
|
||||
Lines.circle(e.x, e.y, c.fin() * 30f);
|
||||
});
|
||||
|
||||
e.scaled(12f, c -> {
|
||||
color(Pal.bulletYellowBack);
|
||||
randLenVectors(e.id, 25, 5f + e.fin() * 80f, e.rotation, 60f, (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, c.fout() * 3f, 45f);
|
||||
});
|
||||
});
|
||||
}),
|
||||
|
||||
hitLaser = new Effect(8, e -> {
|
||||
color(Color.white, Pal.heal, e.fin());
|
||||
stroke(0.5f + e.fout());
|
||||
@@ -1074,28 +1147,11 @@ public class Fx{
|
||||
}),
|
||||
|
||||
railHit = new Effect(18f, 200f, e -> {
|
||||
if(true){
|
||||
color(Pal.orangeSpark);
|
||||
color(Pal.orangeSpark);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i);
|
||||
}
|
||||
}else{
|
||||
e.scaled(7f, b -> {
|
||||
color(Color.white, Color.lightGray, b.fin());
|
||||
stroke(b.fout() * 2f + 0.2f);
|
||||
Lines.circle(b.x, b.y, b.fin() * 28f);
|
||||
});
|
||||
|
||||
color(Pal.orangeSpark);
|
||||
float rot = e.rotation + Mathf.randomSeedRange(e.id, 20f);
|
||||
float w = 9f * e.fout();
|
||||
|
||||
Drawf.tri(e.x, e.y, w, 100f, rot);
|
||||
Drawf.tri(e.x, e.y, w, 10f, rot + 180f);
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i);
|
||||
}
|
||||
|
||||
|
||||
}),
|
||||
|
||||
lancerLaserShoot = new Effect(21f, e -> {
|
||||
@@ -1109,7 +1165,7 @@ public class Fx{
|
||||
|
||||
lancerLaserShootSmoke = new Effect(26f, e -> {
|
||||
color(Color.white);
|
||||
float length = e.data == null || !(e.data instanceof Float) ? 70f : (Float)e.data;
|
||||
float length = !(e.data instanceof Float) ? 70f : (Float)e.data;
|
||||
|
||||
randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> {
|
||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);
|
||||
|
||||
@@ -350,8 +350,10 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
|
||||
node(lancer, () -> {
|
||||
node(meltdown, () -> {
|
||||
node(foreshadow, () -> {
|
||||
node(meltdown, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(shockMine, () -> {
|
||||
|
||||
@@ -175,6 +175,18 @@ public class Units{
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the closest target enemy. First, units are checked, then tile entities. */
|
||||
public static Teamc bestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred, Boolf<Building> tilePred, Sortf sort){
|
||||
if(team == Team.derelict) return null;
|
||||
|
||||
Unit unit = bestEnemy(team, x, y, range, unitPred, sort);
|
||||
if(unit != null){
|
||||
return unit;
|
||||
}else{
|
||||
return findEnemyTile(team, x, y, range, tilePred);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the closest enemy of this team. Filter by predicate. */
|
||||
public static Unit closestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate){
|
||||
if(team == Team.derelict) return null;
|
||||
@@ -195,6 +207,26 @@ public class Units{
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns the closest enemy of this team using a custom comparison function. Filter by predicate. */
|
||||
public static Unit bestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate, Sortf sort){
|
||||
if(team == Team.derelict) return null;
|
||||
|
||||
result = null;
|
||||
cdist = 0f;
|
||||
|
||||
nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> {
|
||||
if(e.dead() || !predicate.get(e)) return;
|
||||
|
||||
float dst2 = sort.cost(e, x, y);
|
||||
if(dst2 < range*range && (result == null || dst2 < cdist)){
|
||||
result = e;
|
||||
cdist = dst2;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns the closest ally of this team. Filter by predicate. No range. */
|
||||
public static Unit closest(Team team, float x, float y, Boolf<Unit> predicate){
|
||||
result = null;
|
||||
@@ -297,4 +329,7 @@ public class Units{
|
||||
nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons);
|
||||
}
|
||||
|
||||
public interface Sortf{
|
||||
float cost(Unit unit, float x, float y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ public abstract class BulletType extends Content{
|
||||
public boolean hittable = true;
|
||||
/** Whether this bullet can be reflected. */
|
||||
public boolean reflectable = true;
|
||||
/** Whether to move the bullet back depending on delta to fix some delta-time realted issues.
|
||||
* Do not change unless you know what you're doing. */
|
||||
public boolean backMove = true;
|
||||
/** Bullet range override. */
|
||||
public float range = -1f;
|
||||
|
||||
@@ -212,7 +215,7 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
if(instantDisappear){
|
||||
b.time(lifetime);
|
||||
b.time = lifetime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +277,11 @@ public abstract class BulletType extends Content{
|
||||
bullet.owner = owner;
|
||||
bullet.team = team;
|
||||
bullet.vel.trns(angle, speed * velocityScl);
|
||||
bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta);
|
||||
if(backMove){
|
||||
bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta);
|
||||
}else{
|
||||
bullet.set(x, y);
|
||||
}
|
||||
bullet.lifetime = lifetime * lifetimeScl;
|
||||
bullet.data = data;
|
||||
bullet.drag = drag;
|
||||
|
||||
70
core/src/mindustry/entities/bullet/PointBulletType.java
Normal file
70
core/src/mindustry/entities/bullet/PointBulletType.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package mindustry.entities.bullet;
|
||||
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public class PointBulletType extends BulletType{
|
||||
private static float cdist = 0f;
|
||||
private static Unit result;
|
||||
|
||||
public float trailSpacing = 10f;
|
||||
|
||||
public PointBulletType(){
|
||||
scaleVelocity = true;
|
||||
lifetime = 100f;
|
||||
collides = false;
|
||||
keepVelocity = false;
|
||||
backMove = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
super.init(b);
|
||||
|
||||
float px = b.x + b.lifetime * b.vel.x,
|
||||
py = b.y + b.lifetime * b.vel.y,
|
||||
rot = b.rotation();
|
||||
|
||||
Geometry.iterateLine(0f, b.x, b.y, px, py, trailSpacing, (x, y) -> {
|
||||
trailEffect.at(x, y, rot);
|
||||
});
|
||||
|
||||
b.time = b.lifetime;
|
||||
b.set(px, py);
|
||||
|
||||
//calculate hit entity
|
||||
|
||||
cdist = 0f;
|
||||
result = null;
|
||||
float range = 1f;
|
||||
|
||||
Units.nearbyEnemies(b.team, px - range, py - range, range*2f, range*2f, e -> {
|
||||
if(e.dead()) return;
|
||||
|
||||
e.hitbox(Tmp.r1);
|
||||
if(!Tmp.r1.contains(px, py)) return;
|
||||
|
||||
float dst = e.dst(px, py) - e.hitSize;
|
||||
if((result == null || dst < cdist)){
|
||||
result = e;
|
||||
cdist = dst;
|
||||
}
|
||||
});
|
||||
|
||||
if(result != null){
|
||||
b.collision(result, px, py);
|
||||
}else{
|
||||
Building build = Vars.world.buildWorld(px, py);
|
||||
if(build != null && build.team != b.team){
|
||||
build.collision(b);
|
||||
}
|
||||
}
|
||||
|
||||
b.remove();
|
||||
|
||||
b.vel.setZero();
|
||||
}
|
||||
}
|
||||
@@ -1213,31 +1213,35 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
@Override
|
||||
public double sense(LAccess sensor){
|
||||
if(sensor == LAccess.x) return x;
|
||||
if(sensor == LAccess.y) return y;
|
||||
if(sensor == LAccess.team) return team.id;
|
||||
if(sensor == LAccess.health) return health;
|
||||
if(sensor == LAccess.maxHealth) return maxHealth();
|
||||
if(sensor == LAccess.efficiency) return efficiency();
|
||||
if(sensor == LAccess.rotation) return rotation;
|
||||
if(sensor == LAccess.totalItems && items != null) return items.total();
|
||||
if(sensor == LAccess.totalLiquids && liquids != null) return liquids.total();
|
||||
if(sensor == LAccess.totalPower && power != null && block.consumes.hasPower()) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
|
||||
if(sensor == LAccess.itemCapacity) return block.itemCapacity;
|
||||
if(sensor == LAccess.liquidCapacity) return block.liquidCapacity;
|
||||
if(sensor == LAccess.powerCapacity) return block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
|
||||
if(sensor == LAccess.powerNetIn && power != null) return power.graph.getLastScaledPowerIn() * 60;
|
||||
if(sensor == LAccess.powerNetOut && power != null) return power.graph.getLastScaledPowerOut() * 60;
|
||||
if(sensor == LAccess.powerNetStored && power != null) return power.graph.getLastPowerStored();
|
||||
if(sensor == LAccess.powerNetCapacity && power != null) return power.graph.getLastCapacity();
|
||||
return 0;
|
||||
return switch(sensor){
|
||||
case x -> x;
|
||||
case y -> y;
|
||||
case team -> team.id;
|
||||
case health -> health;
|
||||
case maxHealth -> maxHealth();
|
||||
case efficiency -> efficiency();
|
||||
case rotation -> rotation;
|
||||
case totalItems -> items == null ? 0 : items.total();
|
||||
case totalLiquids -> liquids == null ? 0 : liquids.total();
|
||||
case totalPower -> power == null || !block.consumes.hasPower() ? 0 : power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
|
||||
case itemCapacity -> block.itemCapacity;
|
||||
case liquidCapacity -> block.liquidCapacity;
|
||||
case powerCapacity -> block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
|
||||
case powerNetIn -> power == null ? 0 : power.graph.getLastScaledPowerIn() * 60;
|
||||
case powerNetOut -> power == null ? 0 : power.graph.getLastScaledPowerOut() * 60;
|
||||
case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored();
|
||||
case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity();
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object senseObject(LAccess sensor){
|
||||
if(sensor == LAccess.type) return block;
|
||||
return switch(sensor){
|
||||
case type -> block;
|
||||
default -> noSensed;
|
||||
};
|
||||
|
||||
return noSensed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -75,24 +75,28 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
@Override
|
||||
public double sense(LAccess sensor){
|
||||
if(sensor == LAccess.totalItems) return stack().amount;
|
||||
if(sensor == LAccess.rotation) return rotation;
|
||||
if(sensor == LAccess.health) return health;
|
||||
if(sensor == LAccess.maxHealth) return maxHealth;
|
||||
if(sensor == LAccess.x) return x;
|
||||
if(sensor == LAccess.y) return y;
|
||||
if(sensor == LAccess.team) return team.id;
|
||||
if(sensor == LAccess.shooting) return isShooting() ? 1 : 0;
|
||||
if(sensor == LAccess.shootX) return aimX();
|
||||
if(sensor == LAccess.shootY) return aimY();
|
||||
return 0;
|
||||
return switch(sensor){
|
||||
case totalItems -> stack().amount;
|
||||
case rotation -> rotation;
|
||||
case health -> health;
|
||||
case maxHealth -> maxHealth;
|
||||
case x -> x;
|
||||
case y -> y;
|
||||
case team -> team.id;
|
||||
case shooting -> isShooting() ? 1 : 0;
|
||||
case shootX -> aimX();
|
||||
case shootY -> aimY();
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object senseObject(LAccess sensor){
|
||||
if(sensor == LAccess.type) return type;
|
||||
return switch(sensor){
|
||||
case type -> type;
|
||||
default -> noSensed;
|
||||
};
|
||||
|
||||
return noSensed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -703,7 +703,7 @@ public class HudFragment extends Fragment{
|
||||
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
|
||||
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f);
|
||||
t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> {
|
||||
b.color.set(player.displayAmmo() ? player.dead() ? Pal.ammo : player.unit().type().ammoType.color : Pal.health);
|
||||
b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type().ammoType.color : Pal.health);
|
||||
});
|
||||
|
||||
t.getChildren().get(1).toFront();
|
||||
|
||||
@@ -14,6 +14,7 @@ import arc.util.io.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.Units.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
@@ -67,6 +68,7 @@ public abstract class Turret extends Block{
|
||||
public float coolantMultiplier = 5f;
|
||||
/** Effect displayed when coolant is used. */
|
||||
public Effect coolEffect = Fx.fuelburn;
|
||||
public Sortf unitSort = Unit::dst2;
|
||||
|
||||
protected Vec2 tr = new Vec2();
|
||||
protected Vec2 tr2 = new Vec2();
|
||||
@@ -306,9 +308,9 @@ public abstract class Turret extends Block{
|
||||
|
||||
protected void findTarget(){
|
||||
if(targetAir && !targetGround){
|
||||
target = Units.closestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded());
|
||||
target = Units.bestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded(), unitSort);
|
||||
}else{
|
||||
target = Units.closestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround));
|
||||
target = Units.bestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround), b -> true, unitSort);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +399,7 @@ public abstract class Turret extends Block{
|
||||
}
|
||||
|
||||
protected void bullet(BulletType type, float angle){
|
||||
float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, targetPos.x, targetPos.y) / type.range(), minRange / type.range(), range / type.range()) : 1f;
|
||||
float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(x + tr.x, y + tr.y, targetPos.x, targetPos.y) / type.range(), minRange / type.range(), range / type.range()) : 1f;
|
||||
|
||||
type.create(this, team, x + tr.x, y + tr.y, angle, 1f + Mathf.range(velocityInaccuracy), lifeScl);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user