diff --git a/core/assets-raw/fontgen/config.json b/core/assets-raw/fontgen/config.json
index f2421542a9..1c25eac26c 100644
--- a/core/assets-raw/fontgen/config.json
+++ b/core/assets-raw/fontgen/config.json
@@ -886,20 +886,6 @@
"command-retreat"
]
},
- {
- "uid": "1bc31b80669cb5edc2ee5d1370554bc9",
- "css": "players",
- "code": 59483,
- "src": "custom_icons",
- "selected": true,
- "svg": {
- "path": "M370.1 55.1Q401.6 23.6 448.8 7.9 496.1-7.9 543.3 7.9 590.6 23.6 622 55.1 653.5 86.6 685 118.1 716.5 149.6 732.3 196.9 748 244.1 732.3 291.3 716.5 338.6 685 370.1 653.5 401.6 653.5 433.1 653.5 464.6 685 496.1 716.5 527.6 748 559.1 779.5 590.6 811 622 842.5 653.5 874 685 905.5 716.5 937 748 968.5 779.5 984.3 826.8 1000 874 984.3 921.3 968.5 968.5 921.3 984.3 874 1000 811 1000 748 1000 685 1000 622 1000 559.1 1000 496.1 1000 433.1 1000 370.1 1000 307.1 1000 244.1 1000 181.1 1000 118.1 1000 70.9 984.3 23.6 968.5 7.9 921.3-7.9 874 7.9 826.8 23.6 779.5 55.1 748 86.6 716.5 118.1 685 149.6 653.5 181.1 622 212.6 590.6 244.1 559.1 275.6 527.6 307.1 496.1 338.6 464.6 338.6 433.1 338.6 401.6 307.1 370.1 275.6 338.6 259.8 291.3 244.1 244.1 259.8 196.9 275.6 149.6 307.1 118.1 338.6 86.6 370.1 55.1",
- "width": 992
- },
- "search": [
- "players"
- ]
- },
{
"uid": "2073dbd997e5d8e1ffc1322d13ba5585",
"css": "chat",
@@ -919,6 +905,34 @@
"css": "zoom",
"code": 59415,
"src": "fontawesome"
+ },
+ {
+ "uid": "1bc31b80669cb5edc2ee5d1370554bc9",
+ "css": "players",
+ "code": 59483,
+ "src": "custom_icons",
+ "selected": true,
+ "svg": {
+ "path": "M370.1 55.1Q401.6 23.6 448.8 7.9 496.1-7.9 543.3 7.9 590.6 23.6 622 55.1 653.5 86.6 685 118.1 716.5 149.6 732.3 196.9 748 244.1 732.3 291.3 716.5 338.6 685 370.1 653.5 401.6 653.5 433.1 653.5 464.6 685 496.1 716.5 527.6 748 559.1 779.5 590.6 811 622 842.5 653.5 874 685 905.5 716.5 937 748 968.5 779.5 984.3 826.8 1000 874 984.3 921.3 968.5 968.5 921.3 984.3 874 1000 811 1000 748 1000 685 1000 622 1000 559.1 1000 496.1 1000 433.1 1000 370.1 1000 307.1 1000 244.1 1000 181.1 1000 118.1 1000 70.9 984.3 23.6 968.5 7.9 921.3-7.9 874 7.9 826.8 23.6 779.5 55.1 748 86.6 716.5 118.1 685 149.6 653.5 181.1 622 212.6 590.6 244.1 559.1 275.6 527.6 307.1 496.1 338.6 464.6 338.6 433.1 338.6 401.6 307.1 370.1 275.6 338.6 259.8 291.3 244.1 244.1 259.8 196.9 275.6 149.6 307.1 118.1 338.6 86.6 370.1 55.1",
+ "width": 992
+ },
+ "search": [
+ "players"
+ ]
+ },
+ {
+ "uid": "dd1e5d774d1ced68cb7c439d8ed102f5",
+ "css": "logic",
+ "code": 59420,
+ "src": "custom_icons",
+ "selected": true,
+ "svg": {
+ "path": "M375 0L250 125H125V250L0 375 125 500 0 625 125 750V875H250L375 1000 500 875 625 1000 750 875H875V750L1000 625 875 500 1000 375 875 250V125H750L625 0 500 125ZM250 250H750V750H250ZM375 375V625H625V375Z",
+ "width": 1000
+ },
+ "search": [
+ "logic"
+ ]
}
]
-}
+}
\ No newline at end of file
diff --git a/core/assets-raw/fontgen/icons/logic.svg b/core/assets-raw/fontgen/icons/logic.svg
new file mode 100644
index 0000000000..431ce25d42
--- /dev/null
+++ b/core/assets-raw/fontgen/icons/logic.svg
@@ -0,0 +1,67 @@
+
+
diff --git a/core/assets-raw/sprites/blocks/logic/switch.png b/core/assets-raw/sprites/blocks/logic/switch.png
index 44d28eedb9..fa193de96d 100644
Binary files a/core/assets-raw/sprites/blocks/logic/switch.png and b/core/assets-raw/sprites/blocks/logic/switch.png differ
diff --git a/core/assets/fonts/font.woff b/core/assets/fonts/font.woff
index a494ce2f71..7960523d0f 100644
Binary files a/core/assets/fonts/font.woff and b/core/assets/fonts/font.woff differ
diff --git a/core/assets/fonts/icon.ttf b/core/assets/fonts/icon.ttf
index 0cde9685b5..4b61658e65 100644
Binary files a/core/assets/fonts/icon.ttf and b/core/assets/fonts/icon.ttf differ
diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java
index c06c1e1a68..ef5958c3c8 100644
--- a/core/src/mindustry/entities/comp/BuildingComp.java
+++ b/core/src/mindustry/entities/comp/BuildingComp.java
@@ -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;
diff --git a/core/src/mindustry/entities/comp/HealthComp.java b/core/src/mindustry/entities/comp/HealthComp.java
index 609f3da46f..ca65ea8115 100644
--- a/core/src/mindustry/entities/comp/HealthComp.java
+++ b/core/src/mindustry/entities/comp/HealthComp.java
@@ -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;
diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java
index 68af3b28a1..ff6c2ea62e 100644
--- a/core/src/mindustry/entities/comp/UnitComp.java
+++ b/core/src/mindustry/entities/comp/UnitComp.java
@@ -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;
}
diff --git a/core/src/mindustry/logic/BinaryOp.java b/core/src/mindustry/logic/BinaryOp.java
index 3f3d0e9f52..97601a231d 100644
--- a/core/src/mindustry/logic/BinaryOp.java
+++ b/core/src/mindustry/logic/BinaryOp.java
@@ -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();
diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java
index c620970b6e..ebe16e8162 100644
--- a/core/src/mindustry/logic/LAccess.java
+++ b/core/src/mindustry/logic/LAccess.java
@@ -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
diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java
index 07ddacf3d8..fe2f9250bd 100644
--- a/core/src/mindustry/logic/LExecutor.java
+++ b/core/src/mindustry/logic/LExecutor.java
@@ -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;
diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java
index b9afb48006..8e3c582841 100644
--- a/core/src/mindustry/logic/LStatements.java
+++ b/core/src/mindustry/logic/LStatements.java
@@ -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 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";
diff --git a/core/src/mindustry/logic/RadarSort.java b/core/src/mindustry/logic/RadarSort.java
new file mode 100644
index 0000000000..0b14143065
--- /dev/null
+++ b/core/src/mindustry/logic/RadarSort.java
@@ -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);
+ }
+}
diff --git a/core/src/mindustry/logic/RadarTarget.java b/core/src/mindustry/logic/RadarTarget.java
new file mode 100644
index 0000000000..5c82064fae
--- /dev/null
+++ b/core/src/mindustry/logic/RadarTarget.java
@@ -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);
+ }
+}
diff --git a/core/src/mindustry/logic/Ranged.java b/core/src/mindustry/logic/Ranged.java
new file mode 100644
index 0000000000..7c1f17a903
--- /dev/null
+++ b/core/src/mindustry/logic/Ranged.java
@@ -0,0 +1,7 @@
+package mindustry.logic;
+
+import mindustry.gen.*;
+
+public interface Ranged extends Posc, Teamc{
+ float range();
+}
diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
index fd62367feb..62feb06683 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
@@ -44,10 +44,5 @@ public class PowerTurret extends Turret{
public BulletType peekAmmo(){
return shootType;
}
-
- @Override
- protected float baseReloadSpeed(){
- return cheating() ? 1f : power.status;
- }
}
}
diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
index 337fcb9127..c035018b44 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
@@ -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 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
diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java
index 5d9a4abe7e..29c0a9d9bc 100644
--- a/core/src/mindustry/world/blocks/logic/LogicBlock.java
+++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java
@@ -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);
}
diff --git a/core/src/mindustry/world/blocks/logic/MemoryBlock.java b/core/src/mindustry/world/blocks/logic/MemoryBlock.java
new file mode 100644
index 0000000000..83b2088690
--- /dev/null
+++ b/core/src/mindustry/world/blocks/logic/MemoryBlock.java
@@ -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();
+ }
+ }
+ }
+}