Turret-based radar
This commit is contained in:
@@ -1176,7 +1176,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
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) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
|
||||
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;
|
||||
|
||||
@@ -6,7 +6,7 @@ import mindustry.annotations.Annotations.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
@Component
|
||||
abstract class HealthComp implements Entityc{
|
||||
abstract class HealthComp implements Entityc, Posc{
|
||||
static final float hitDuration = 9f;
|
||||
|
||||
float health;
|
||||
|
||||
@@ -75,6 +75,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
if(sensor == LAccess.health) return health;
|
||||
if(sensor == LAccess.x) return x;
|
||||
if(sensor == LAccess.y) return y;
|
||||
if(sensor == LAccess.shooting) return isShooting() ? 1 : 0;
|
||||
if(sensor == LAccess.shootX) return aimX();
|
||||
if(sensor == LAccess.shootY) return aimY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.math.*;
|
||||
|
||||
public enum BinaryOp{
|
||||
add("+", (a, b) -> a + b),
|
||||
sub("-", (a, b) -> a - b),
|
||||
@@ -20,7 +22,8 @@ public enum BinaryOp{
|
||||
xor("xor", (a, b) -> (int)a ^ (int)b),
|
||||
max("max", Math::max),
|
||||
min("min", Math::min),
|
||||
atan2("atan2", Math::atan2);
|
||||
atan2("atan2", (x, y) -> Mathf.atan2((float)x, (float)y) * Mathf.radDeg),
|
||||
dst("dst", (x, y) -> Mathf.dst((float)x, (float)y));
|
||||
|
||||
public static final BinaryOp[] all = values();
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ public enum LAccess{
|
||||
rotation,
|
||||
x,
|
||||
y,
|
||||
shootX,
|
||||
shootY,
|
||||
shooting,
|
||||
|
||||
//values with parameters are considered controllable
|
||||
enabled("to"), //"to" is standard for single parameter access
|
||||
|
||||
@@ -5,10 +5,14 @@ import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.logic.LogicDisplay.*;
|
||||
import mindustry.world.blocks.logic.MessageBlock.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class LExecutor{
|
||||
//special variables
|
||||
public static final int
|
||||
@@ -87,7 +91,7 @@ public class LExecutor{
|
||||
|
||||
double num(int index){
|
||||
Var v = vars[index];
|
||||
return v.isobj ? 0 : v.numval;
|
||||
return v.isobj ? 1 : v.numval;
|
||||
}
|
||||
|
||||
int numi(int index){
|
||||
@@ -229,6 +233,85 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class RadarI implements LInstruction{
|
||||
public RadarTarget target1 = RadarTarget.enemy, target2 = RadarTarget.any, target3 = RadarTarget.any;
|
||||
public RadarSort sort = RadarSort.distance;
|
||||
public int radar, sortOrder, output;
|
||||
|
||||
//radar instructions are special in that they cache their output and only change it at fixed intervals.
|
||||
//this prevents lag from spam of radar instructions
|
||||
public Healthc lastTarget;
|
||||
public Interval timer = new Interval();
|
||||
|
||||
static float bestValue = 0f;
|
||||
static Unit best = null;
|
||||
|
||||
public RadarI(RadarTarget target1, RadarTarget target2, RadarTarget target3, RadarSort sort, int radar, int sortOrder, int output){
|
||||
this.target1 = target1;
|
||||
this.target2 = target2;
|
||||
this.target3 = target3;
|
||||
this.sort = sort;
|
||||
this.radar = radar;
|
||||
this.sortOrder = sortOrder;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public RadarI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
Building target = exec.building(radar);
|
||||
|
||||
int sortDir = exec.bool(sortOrder) ? 1 : -1;
|
||||
|
||||
if(target instanceof Ranged){
|
||||
float range = ((Ranged)target).range();
|
||||
|
||||
Healthc targeted;
|
||||
|
||||
if(timer.get(20f)){
|
||||
//if any of the targets involve enemies
|
||||
boolean enemies = target1 == RadarTarget.enemy || target2 == RadarTarget.enemy || target3 == RadarTarget.enemy;
|
||||
|
||||
best = null;
|
||||
bestValue = 0;
|
||||
|
||||
if(enemies){
|
||||
for(Team enemy : state.teams.enemiesOf(target.team)){
|
||||
find(target, range, sortDir, enemy);
|
||||
}
|
||||
}else{
|
||||
find(target, range, sortDir, target.team);
|
||||
}
|
||||
|
||||
lastTarget = targeted = best;
|
||||
}else{
|
||||
targeted = lastTarget;
|
||||
}
|
||||
|
||||
exec.setobj(output, targeted);
|
||||
}
|
||||
}
|
||||
|
||||
void find(Building b, float range, int sortDir, Team team){
|
||||
Units.nearby(team, b.x, b.y, range, u -> {
|
||||
boolean valid =
|
||||
target1.func.get(b.team, u) &&
|
||||
target2.func.get(b.team, u) &&
|
||||
target3.func.get(b.team, u);
|
||||
|
||||
if(!valid) return;
|
||||
|
||||
float val = sort.func.get(b, u) * sortDir;
|
||||
if(val > bestValue || best == null){
|
||||
bestValue = val;
|
||||
best = u;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetI implements LInstruction{
|
||||
public int from, to;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.scene.ui.*;
|
||||
@@ -266,7 +267,7 @@ public class LStatements{
|
||||
|
||||
table.left();
|
||||
|
||||
table.add("set ");
|
||||
table.add(" set ");
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> type.name());
|
||||
@@ -304,6 +305,62 @@ public class LStatements{
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("radar")
|
||||
public static class RadarStatement extends LStatement{
|
||||
public RadarTarget target1 = RadarTarget.enemy, target2 = RadarTarget.any, target3 = RadarTarget.any;
|
||||
public RadarSort sort = RadarSort.distance;
|
||||
public String radar = "@0", sortOrder = "0", output = "result";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
table.defaults().left();
|
||||
|
||||
table.add(" from ");
|
||||
|
||||
fields(table, radar, v -> radar = v);
|
||||
|
||||
table.row();
|
||||
|
||||
for(int i = 0; i < 3; i++){
|
||||
int fi = i;
|
||||
Prov<RadarTarget> get = () -> (fi == 0 ? target1 : fi == 1 ? target2 : target3);
|
||||
|
||||
table.add(i == 0 ? " target " : " and ");
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> get.get().name());
|
||||
b.clicked(() -> showSelect(b, RadarTarget.all, get.get(), t -> {
|
||||
if(fi == 0) target1 = t; else if(fi == 1) target2 = t; else target3 = t;
|
||||
}, 2, cell -> cell.size(100, 50)));
|
||||
}, Styles.logict, () -> {}).size(90, 40).color(table.color).left().padLeft(2);
|
||||
|
||||
if(i == 1){
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
table.add(" order ");
|
||||
|
||||
fields(table, sortOrder, v -> sortOrder = v);
|
||||
|
||||
table.row();
|
||||
|
||||
table.add(" output ");
|
||||
|
||||
fields(table, output, v -> output = v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new RadarI(target1, target2, target3, sort, builder.var(radar), builder.var(sortOrder), builder.var(output));
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("sensor")
|
||||
public static class SensorStatement extends LStatement{
|
||||
public String to = "result";
|
||||
|
||||
20
core/src/mindustry/logic/RadarSort.java
Normal file
20
core/src/mindustry/logic/RadarSort.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.math.geom.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public enum RadarSort{
|
||||
distance((pos, other) -> -pos.dst2(other)),
|
||||
health((pos, other) -> other.health()),
|
||||
maxHealth((pos, other) -> other.maxHealth());
|
||||
|
||||
public final RadarSortFunc func;
|
||||
|
||||
RadarSort(RadarSortFunc func){
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public interface RadarSortFunc{
|
||||
float get(Position pos, Healthc other);
|
||||
}
|
||||
}
|
||||
25
core/src/mindustry/logic/RadarTarget.java
Normal file
25
core/src/mindustry/logic/RadarTarget.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public enum RadarTarget{
|
||||
any((team, other) -> true),
|
||||
enemy((team, other) -> team != other.team),
|
||||
ally((team, other) -> team == other.team),
|
||||
player((team, other) -> other.isPlayer()),
|
||||
flying((team, other) -> other.isFlying()),
|
||||
ground((team, other) -> other.isGrounded());
|
||||
|
||||
public final RadarTargetFunc func;
|
||||
|
||||
public static final RadarTarget[] all = values();
|
||||
|
||||
RadarTarget(RadarTargetFunc func){
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public interface RadarTargetFunc{
|
||||
boolean get(Team team, Unit other);
|
||||
}
|
||||
}
|
||||
7
core/src/mindustry/logic/Ranged.java
Normal file
7
core/src/mindustry/logic/Ranged.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import mindustry.gen.*;
|
||||
|
||||
public interface Ranged extends Posc, Teamc{
|
||||
float range();
|
||||
}
|
||||
@@ -44,10 +44,5 @@ public class PowerTurret extends Turret{
|
||||
public BulletType peekAmmo(){
|
||||
return shootType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float baseReloadSpeed(){
|
||||
return cheating() ? 1f : power.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public abstract class Turret extends Block{
|
||||
public abstract BulletType type();
|
||||
}
|
||||
|
||||
public class TurretEntity extends Building implements ControlBlock{
|
||||
public class TurretEntity extends Building implements ControlBlock, Ranged{
|
||||
public Seq<AmmoEntry> ammo = new Seq<>();
|
||||
public int totalAmmo;
|
||||
public float reload, rotation = 90, recoil, heat, logicControlTime = -1;
|
||||
@@ -151,6 +151,11 @@ public abstract class Turret extends Block{
|
||||
public Vec2 targetPos = new Vec2();
|
||||
public @NonNull BlockUnitc unit = Nulls.blockUnit;
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(){
|
||||
unit = (BlockUnitc)UnitTypes.block.create(team);
|
||||
@@ -168,6 +173,15 @@ public abstract class Turret extends Block{
|
||||
super.control(type, p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sense(LAccess sensor){
|
||||
if(sensor == LAccess.shootX) return targetPos.x;
|
||||
if(sensor == LAccess.shootY) return targetPos.y;
|
||||
if(sensor == LAccess.shooting) return (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : validateTarget()) ? 1 : 0;
|
||||
|
||||
return super.sense(sensor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unit unit(){
|
||||
return (Unit)unit;
|
||||
@@ -407,7 +421,7 @@ public abstract class Turret extends Block{
|
||||
}
|
||||
|
||||
protected float baseReloadSpeed(){
|
||||
return 1f;
|
||||
return efficiency();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -67,6 +67,7 @@ public class LogicBlock extends Block{
|
||||
public LExecutor executor = new LExecutor();
|
||||
public float accumulator = 0;
|
||||
public IntSeq connections = new IntSeq();
|
||||
public IntSeq invalidConnections = new IntSeq();
|
||||
public boolean loaded = false;
|
||||
|
||||
public LogicEntity(){
|
||||
@@ -130,6 +131,22 @@ public class LogicBlock extends Block{
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
//check for previously invalid links to add after configuration
|
||||
removal.clear();
|
||||
|
||||
for(int i = 0; i < invalidConnections.size; i++){
|
||||
int val = invalidConnections.get(i);
|
||||
if(validLink(val) && !connections.contains(val)){
|
||||
removal.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
if(!removal.isEmpty()){
|
||||
connections.addAll(removal);
|
||||
invalidConnections.removeAll(removal);
|
||||
updateCode(code);
|
||||
}
|
||||
|
||||
//remove invalid links
|
||||
removal.clear();
|
||||
|
||||
@@ -141,11 +158,11 @@ public class LogicBlock extends Block{
|
||||
}
|
||||
|
||||
if(!removal.isEmpty()){
|
||||
invalidConnections.addAll(removal);
|
||||
connections.removeAll(removal);
|
||||
updateCode(code);
|
||||
}
|
||||
|
||||
connections.removeAll(removal);
|
||||
|
||||
accumulator += edelta() * instructionsPerTick;
|
||||
|
||||
if(accumulator > maxInstructionScale * instructionsPerTick) accumulator = maxInstructionScale * instructionsPerTick;
|
||||
@@ -258,6 +275,7 @@ public class LogicBlock extends Block{
|
||||
write.str(v.name);
|
||||
|
||||
Object value = v.isobj ? v.objval : v.numval;
|
||||
if(value instanceof Unit) value = null; //do not save units.
|
||||
TypeIO.writeObject(write, value);
|
||||
}
|
||||
|
||||
|
||||
39
core/src/mindustry/world/blocks/logic/MemoryBlock.java
Normal file
39
core/src/mindustry/world/blocks/logic/MemoryBlock.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package mindustry.world.blocks.logic;
|
||||
|
||||
import arc.util.io.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
public class MemoryBlock extends Block{
|
||||
public int memoryCapacity = 32;
|
||||
|
||||
public MemoryBlock(String name){
|
||||
super(name);
|
||||
destructible = true;
|
||||
}
|
||||
|
||||
public class MemoryEntity extends Building{
|
||||
public double[] memory = new double[memoryCapacity];
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
super.write(write);
|
||||
|
||||
write.i(memory.length);
|
||||
for(double v : memory){
|
||||
write.d(v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(Reads read, byte revision){
|
||||
super.read(read, revision);
|
||||
|
||||
int amount = read.i();
|
||||
memory = memory.length != amount ? new double[amount] : memory;
|
||||
for(int i = 0; i < amount; i++){
|
||||
memory[i] = read.d();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user