From ea8dccdfb274b3fb8622896665587826d7ed9543 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 10 Aug 2020 14:19:24 -0400 Subject: [PATCH] Many various logic changes --- .../mindustry/entities/comp/BuildingComp.java | 36 ++-- .../src/mindustry/entities/comp/UnitComp.java | 6 +- core/src/mindustry/io/TypeIO.java | 8 +- core/src/mindustry/logic/Controllable.java | 6 + core/src/mindustry/logic/LAccess.java | 35 ++++ core/src/mindustry/logic/LAssembler.java | 47 ++++- core/src/mindustry/logic/LCanvas.java | 7 - core/src/mindustry/logic/LExecutor.java | 141 +++++++++----- core/src/mindustry/logic/LSensor.java | 19 -- core/src/mindustry/logic/LStatement.java | 6 +- core/src/mindustry/logic/LStatements.java | 182 ++++++++++++------ core/src/mindustry/logic/Senseable.java | 2 +- .../mindustry/world/blocks/defense/Door.java | 23 ++- .../world/blocks/defense/turrets/Turret.java | 33 +++- .../world/blocks/logic/LogicDisplay.java | 11 +- .../world/blocks/power/NuclearReactor.java | 4 +- 16 files changed, 384 insertions(+), 182 deletions(-) create mode 100644 core/src/mindustry/logic/Controllable.java create mode 100644 core/src/mindustry/logic/LAccess.java delete mode 100644 core/src/mindustry/logic/LSensor.java diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 628972d948..6f1e6d0d68 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -39,7 +39,7 @@ import static mindustry.Vars.*; @EntityDef(value = {Buildingc.class}, isFinal = false, genio = false, serialize = false) @Component(base = true) -abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Senseable{ +abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Senseable, Controllable{ //region vars and initialization static final float timeToSleep = 60f * 1; static final ObjectSet tmpTiles = new ObjectSet<>(); @@ -1168,19 +1168,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } @Override - public double sense(LSensor sensor){ - if(sensor == LSensor.health) return health; - if(sensor == LSensor.efficiency) return efficiency(); - if(sensor == LSensor.totalItems && items != null) return items.total(); - if(sensor == LSensor.totalLiquids && liquids != null) return liquids.total(); - if(sensor == LSensor.totalPower && power != null) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f); - if(sensor == LSensor.itemCapacity) return block.itemCapacity; - if(sensor == LSensor.liquidCapacity) return block.liquidCapacity; - if(sensor == LSensor.powerCapacity) return block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f; - if(sensor == LSensor.powerNetIn && power != null) return power.graph.getPowerProduced(); - if(sensor == LSensor.powerNetOut && power != null) return power.graph.getPowerNeeded(); - if(sensor == LSensor.powerNetStored && power != null) return power.graph.getLastPowerStored(); - if(sensor == LSensor.powerNetCapacity && power != null) return power.graph.getBatteryCapacity(); + public double sense(LAccess sensor){ + if(sensor == LAccess.health) return health; + 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) 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.getPowerProduced(); + if(sensor == LAccess.powerNetOut && power != null) return power.graph.getPowerNeeded(); + if(sensor == LAccess.powerNetStored && power != null) return power.graph.getLastPowerStored(); + if(sensor == LAccess.powerNetCapacity && power != null) return power.graph.getBatteryCapacity(); return 0; } @@ -1191,6 +1192,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return 0; } + @Override + public void control(LAccess type, double p1, double p2, double p3, double p4){ + if(type == LAccess.enabled){ + enabled = !Mathf.zero((float)p1); + } + } + @Override public void remove(){ if(sound != null){ diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index c10880a813..a863521830 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -70,9 +70,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I } @Override - public double sense(LSensor sensor){ - if(sensor == LSensor.totalItems) return stack().amount; - if(sensor == LSensor.health) return health; + public double sense(LAccess sensor){ + if(sensor == LAccess.totalItems) return stack().amount; + if(sensor == LAccess.health) return health; return 0; } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index e7291c7df8..9091320c5d 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -86,9 +86,9 @@ public class TypeIO{ }else if(object instanceof Building){ write.b((byte)12); write.i(((Building)object).pos()); - }else if(object instanceof LSensor){ + }else if(object instanceof LAccess){ write.b((byte)13); - write.s(((LSensor)object).ordinal()); + write.s(((LAccess)object).ordinal()); }else{ throw new IllegalArgumentException("Unknown object type: " + object.getClass()); } @@ -111,7 +111,7 @@ public class TypeIO{ case 10: return read.bool(); case 11: return read.d(); case 12: return world.build(read.i()); - case 13: return LSensor.all[read.s()]; + case 13: return LAccess.all[read.s()]; default: throw new IllegalArgumentException("Unknown object type: " + type); } } @@ -303,7 +303,7 @@ public class TypeIO{ //make sure player exists if(player == null) return prev; return player; - }else if(type == 1){ + }else if(type == 1){ //formation controller int id = read.i(); return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null); }else{ diff --git a/core/src/mindustry/logic/Controllable.java b/core/src/mindustry/logic/Controllable.java new file mode 100644 index 0000000000..31baf31a1e --- /dev/null +++ b/core/src/mindustry/logic/Controllable.java @@ -0,0 +1,6 @@ +package mindustry.logic; + +/** An object that can be controlled with logic. */ +public interface Controllable{ + void control(LAccess type, double p1, double p2, double p3, double p4); +} diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java new file mode 100644 index 0000000000..a0bbe36319 --- /dev/null +++ b/core/src/mindustry/logic/LAccess.java @@ -0,0 +1,35 @@ +package mindustry.logic; + +import arc.struct.*; + +/** Setter/getter enum for logic-controlled objects. */ +public enum LAccess{ + totalItems, + totalLiquids, + totalPower, + itemCapacity, + liquidCapacity, + powerCapacity, + powerNetStored, + powerNetCapacity, + powerNetIn, + powerNetOut, + health, + heat, + efficiency, + rotation, + + //values with parameters are considered controllable + enabled("to"), + shoot("x", "y", "shoot"); + + public final String[] parameters; + + public static final LAccess[] all = values(); + public static final LAccess[] senseable = Seq.select(all, t -> t.parameters.length <= 1).toArray(LAccess.class); + public static final LAccess[] controls = Seq.select(all, t -> t.parameters.length > 0).toArray(LAccess.class); + + LAccess(String... parameters){ + this.parameters = parameters; + } +} diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index 733a5ff760..247ab8984f 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -6,6 +6,7 @@ import arc.util.ArcAnnotate.*; import mindustry.*; import mindustry.gen.*; import mindustry.logic.LExecutor.*; +import mindustry.logic.LStatements.*; import mindustry.type.*; /** "Compiles" a sequence of statements into instructions. */ @@ -39,7 +40,7 @@ public class LAssembler{ //store sensor constants - for(LSensor sensor : LSensor.all){ + for(LAccess sensor : LAccess.all){ putConst("@" + sensor.name(), sensor); } } @@ -64,22 +65,48 @@ public class LAssembler{ } public static Seq read(String data){ + //empty data check + if(data == null || data.isEmpty()) return new Seq<>(); + Seq statements = new Seq<>(); String[] lines = data.split("[;\n]+"); for(String line : lines){ //comments if(line.startsWith("#")) continue; - String[] tokens = line.split(" "); - LStatement st = LogicIO.read(tokens); - if(st != null){ - statements.add(st); - }else{ - //attempt parsing using custom parser if a match is found - this is for mods - String first = tokens[0]; - if(customParsers.containsKey(first)){ - statements.add(customParsers.get(first).get(tokens)); + try{ + //yes, I am aware that this can be split with regex, but that's slow and even more incomprehensible + Seq tokens = new Seq<>(); + boolean inString = false; + int lastIdx = 0; + + for(int i = 0; i < line.length() + 1; i++){ + char c = i == line.length() ? ' ' : line.charAt(i); + if(c == '"'){ + inString = !inString; + }else if(c == ' ' && !inString){ + tokens.add(line.substring(lastIdx, i).replace("\\n", "\n")); + lastIdx = i + 1; + } } + + String[] arr = tokens.toArray(String.class); + LStatement st = LogicIO.read(arr); + if(st != null){ + statements.add(st); + }else{ + //attempt parsing using custom parser if a match is found - this is for mods + String first = arr[0]; + if(customParsers.containsKey(first)){ + statements.add(customParsers.get(first).get(arr)); + }else{ + //unparseable statement + statements.add(new InvalidStatement()); + } + } + }catch(Exception parseFailed){ + //when parsing fails, add a dummy invalid statement + statements.add(new InvalidStatement()); } } return statements; diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java index 0c0483782d..cd4add83e9 100644 --- a/core/src/mindustry/logic/LCanvas.java +++ b/core/src/mindustry/logic/LCanvas.java @@ -16,7 +16,6 @@ import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.logic.LStatements.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; @@ -56,12 +55,6 @@ public class LCanvas extends Table{ dialog.addCloseButton(); dialog.show(); }).height(50f).left().width(400f).marginLeft(10f); - - add(new PrintStatement()); - add(new SetStatement()); - add(new JumpStatement()); - add(new EnableStatement()); - add(new BinaryOpStatement()); } private void drawGrid(){ diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 9abe2b7f8e..02c68708e2 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -7,8 +7,7 @@ import mindustry.*; import mindustry.ctype.*; import mindustry.gen.*; import mindustry.world.blocks.logic.LogicDisplay.*; - -import static mindustry.world.blocks.logic.LogicDisplay.*; +import mindustry.world.blocks.storage.MessageBlock.*; public class LExecutor{ //special variables @@ -16,10 +15,16 @@ public class LExecutor{ varCounter = 0, varTime = 1; + public static final int + maxGraphicsBuffer = 512, + maxTextBuffer = 256; + public double[] memory = {}; public LInstruction[] instructions = {}; public Var[] vars = {}; + public LongSeq graphicsBuffer = new LongSeq(); + public StringBuilder textBuffer = new StringBuilder(); public boolean initialized(){ return instructions != null && vars != null && instructions.length > 0; @@ -125,21 +130,30 @@ public class LExecutor{ void run(LExecutor exec); } - /** Enables/disables a building. */ - public static class EnableI implements LInstruction{ - public int target, value; + /** Controls a building's state. */ + public static class ControlI implements LInstruction{ + public int target; + public LAccess type = LAccess.enabled; + public int p1, p2, p3, p4; - public EnableI(int target, int value){ + public ControlI(LAccess type, int target, int p1, int p2, int p3, int p4){ + this.type = type; this.target = target; - this.value = value; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; } - EnableI(){} + ControlI(){} @Override public void run(LExecutor exec){ - Building b = exec.building(target); - if(b != null) b.enabled = exec.bool(value); + Object obj = exec.obj(target); + if(obj instanceof Controllable){ + Controllable cont = (Controllable)obj; + cont.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4)); + } } } @@ -205,8 +219,8 @@ public class LExecutor{ if(target instanceof Senseable){ if(sense instanceof Content){ output = ((Senseable)target).sense(((Content)sense)); - }else if(sense instanceof LSensor){ - output = ((Senseable)target).sense(((LSensor)sense)); + }else if(sense instanceof LAccess){ + output = ((Senseable)target).sense(((LAccess)sense)); } } @@ -288,12 +302,17 @@ public class LExecutor{ } } - public static class DisplayI implements LInstruction{ + public static class NoopI implements LInstruction{ + @Override + public void run(LExecutor exec){} + } + + public static class DrawI implements LInstruction{ public byte type; public int target; public int x, y, p1, p2, p3; - public DisplayI(byte type, int target, int x, int y, int p1, int p2, int p3){ + public DrawI(byte type, int target, int x, int y, int p1, int p2, int p3){ this.type = type; this.target = target; this.x = x; @@ -303,7 +322,7 @@ public class LExecutor{ this.p3 = p3; } - public DisplayI(){ + public DrawI(){ } @Override @@ -311,63 +330,91 @@ public class LExecutor{ //graphics on headless servers are useless. if(Vars.headless) return; - if(type == commandFlush){ - Building build = exec.building(target); - if(build instanceof LogicDisplayEntity){ - //flush is a special command - LogicDisplayEntity d = (LogicDisplayEntity)build; - for(int i = 0; i < exec.graphicsBuffer.size; i++){ - d.commands.addLast(exec.graphicsBuffer.items[i]); - } - exec.graphicsBuffer.clear(); - } + //add graphics calls, cap graphics buffer size + if(exec.graphicsBuffer.size < maxGraphicsBuffer){ + exec.graphicsBuffer.add(DisplayCmd.get(type, exec.numi(x), exec.numi(y), exec.numi(p1), exec.numi(p2), exec.numi(p3))); + } + } + } - }else{ - //add graphics calls, cap graphics buffer size - if(exec.graphicsBuffer.size < 1024){ - exec.graphicsBuffer.add(DisplayCmd.get(type, exec.numi(x), exec.numi(y), exec.numi(p1), exec.numi(p2), exec.numi(p3))); + public static class DrawFlushI implements LInstruction{ + public int target; + + public DrawFlushI(int target){ + this.target = target; + } + + public DrawFlushI(){ + } + + @Override + public void run(LExecutor exec){ + //graphics on headless servers are useless. + if(Vars.headless) return; + + Building build = exec.building(target); + if(build instanceof LogicDisplayEntity){ + LogicDisplayEntity d = (LogicDisplayEntity)build; + for(int i = 0; i < exec.graphicsBuffer.size; i++){ + d.commands.addLast(exec.graphicsBuffer.items[i]); } + exec.graphicsBuffer.clear(); } } } public static class PrintI implements LInstruction{ - private static final StringBuilder out = new StringBuilder(); + public int value; - public int value, target; - - public PrintI(int value, int target){ + public PrintI(int value){ this.value = value; - this.target = target; } PrintI(){} @Override public void run(LExecutor exec){ - Building b = exec.building(target); - if(b == null) return; + if(exec.textBuffer.length() >= maxTextBuffer) return; //this should avoid any garbage allocation Var v = exec.vars[value]; if(v.isobj && value != 0){ - if(v.objval instanceof String){ - b.handleString(v.objval); - }else if(v.objval == null){ - b.handleString("null"); - }else{ - b.handleString("[object]"); - } + String strValue = v.objval instanceof String ? (String)v.objval : v.objval == null ? "null" : "[object]"; + + exec.textBuffer.append(strValue); }else{ - out.setLength(0); //display integer version when possible if(Math.abs(v.numval - (long)v.numval) < 0.000001){ - out.append((long)v.numval); + exec.textBuffer.append((long)v.numval); }else{ - out.append(v.numval); + exec.textBuffer.append(v.numval); } - b.handleString(out); + } + } + } + + public static class PrintFlushI implements LInstruction{ + public int target; + + public PrintFlushI(int target){ + this.target = target; + } + + public PrintFlushI(){ + } + + @Override + public void run(LExecutor exec){ + + Building build = exec.building(target); + if(build instanceof MessageBlockEntity){ + MessageBlockEntity d = (MessageBlockEntity)build; + + d.message.setLength(0); + d.message.append(exec.textBuffer, 0, Math.min(exec.textBuffer.length(), maxTextBuffer)); + + exec.textBuffer.setLength(0); } } } diff --git a/core/src/mindustry/logic/LSensor.java b/core/src/mindustry/logic/LSensor.java deleted file mode 100644 index b81cdb8d0e..0000000000 --- a/core/src/mindustry/logic/LSensor.java +++ /dev/null @@ -1,19 +0,0 @@ -package mindustry.logic; - -public enum LSensor{ - totalItems, - totalLiquids, - totalPower, - itemCapacity, - liquidCapacity, - powerCapacity, - powerNetStored, - powerNetCapacity, - powerNetIn, - powerNetOut, - health, - heat, - efficiency; - - public static final LSensor[] all = values(); -} diff --git a/core/src/mindustry/logic/LStatement.java b/core/src/mindustry/logic/LStatement.java index 985fbc4da9..884c1a19f9 100644 --- a/core/src/mindustry/logic/LStatement.java +++ b/core/src/mindustry/logic/LStatement.java @@ -7,6 +7,7 @@ import arc.scene.*; import arc.scene.actions.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import mindustry.gen.*; @@ -27,9 +28,8 @@ public abstract class LStatement{ public LStatement copy(){ StringBuilder build = new StringBuilder(); write(build); - String[] split = build.toString().split(" "); - LStatement result = LogicIO.read(split); - return result == null && LAssembler.customParsers.containsKey(split[0]) ? LAssembler.customParsers.get(split[0]).get(split) : result; + Seq read = LAssembler.read(build.toString()); + return read.size == 0 ? null : read.first(); } //protected methods are only for internal UI layout utilities diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index ab155971de..882f2ef9f2 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -37,6 +37,24 @@ public class LStatements{ } } + @RegisterStatement("noop") + public static class InvalidStatement extends LStatement{ + + @Override + public void build(Table table){ + } + + @Override + public LCategory category(){ + return LCategory.operations; + } + + @Override + public LInstruction build(LAssembler builder){ + return new NoopI(); + } + } + @RegisterStatement("write") public static class WriteStatement extends LStatement{ public String to = "0"; @@ -90,7 +108,7 @@ public class LStatements{ @RegisterStatement("draw") public static class DrawStatement extends LStatement{ - public CommandType type = CommandType.line; + public GraphicsType type = GraphicsType.line; public String x = "0", y = "0", p1 = "0", p2 = "0", p3 = "0"; @Override @@ -105,13 +123,13 @@ public class LStatements{ table.button(b -> { b.label(() -> type.name()); - b.clicked(() -> showSelect(b, CommandType.allNormal, type, t -> { + b.clicked(() -> showSelect(b, GraphicsType.all, type, t -> { type = t; rebuild(table); }, 2, cell -> cell.size(100, 50))); }, Styles.logict, () -> {}).size(90, 40).color(table.color).left().padLeft(2); - if(type != CommandType.stroke){ + if(type != GraphicsType.stroke){ table.row(); } @@ -158,7 +176,6 @@ public class LStatements{ } }).expand().left(); - } @Override @@ -168,13 +185,13 @@ public class LStatements{ @Override public LInstruction build(LAssembler builder){ - return new DisplayI((byte)type.ordinal(), 0, builder.var(x), builder.var(y), builder.var(p1), builder.var(p2), builder.var(p3)); + return new DrawI((byte)type.ordinal(), 0, builder.var(x), builder.var(y), builder.var(p1), builder.var(p2), builder.var(p3)); } } - @RegisterStatement("flush") - public static class FlushStatement extends LStatement{ - public String target = "display"; + @RegisterStatement("drawflush") + public static class DrawFlushStatement extends LStatement{ + public String target = "@0"; @Override public void build(Table table){ @@ -189,7 +206,102 @@ public class LStatements{ @Override public LInstruction build(LAssembler builder){ - return new DisplayI(commandFlush, builder.var(target), 0, 0, 0, 0, 0); + return new DrawFlushI(builder.var(target)); + } + } + + @RegisterStatement("print") + public static class PrintStatement extends LStatement{ + public String value = "\"frog\""; + + @Override + public void build(Table table){ + field(table, value, str -> value = str).width(0f).growX().padRight(3); + } + + @Override + public LInstruction build(LAssembler builder){ + return new PrintI(builder.var(value)); + } + + @Override + public LCategory category(){ + return LCategory.control; + } + } + + @RegisterStatement("printflush") + public static class PrintFlushStatement extends LStatement{ + public String target = "@0"; + + @Override + public void build(Table table){ + table.add(" to "); + field(table, target, str -> target = str); + } + + @Override + public LCategory category(){ + return LCategory.blocks; + } + + @Override + public LInstruction build(LAssembler builder){ + return new PrintFlushI(builder.var(target)); + } + } + + @RegisterStatement("control") + public static class ControlStatement extends LStatement{ + public LAccess type = LAccess.enabled; + public String target = "@0", p1 = "0", p2 = "0", p3 = "0", p4 = "0"; + + @Override + public void build(Table table){ + rebuild(table); + } + + void rebuild(Table table){ + table.clearChildren(); + + table.left(); + + table.add(" set "); + + table.button(b -> { + b.label(() -> type.name()); + b.clicked(() -> showSelect(b, LAccess.controls, type, t -> { + type = t; + rebuild(table); + }, 2, cell -> cell.size(100, 50))); + }, Styles.logict, () -> { + }).size(90, 40).color(table.color).left().padLeft(2); + + table.add(" of "); + + field(table, target, v -> target = v); + + table.row(); + + //Q: why don't you just use arrays for this? + //A: arrays aren't as easy to serialize so the code generator doesn't handle them + int c = 0; + for(int i = 0; i < type.parameters.length; i++){ + + fields(table, type.parameters[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v); + + if(++c % 2 == 0) table.row(); + } + } + + @Override + public LCategory category(){ + return LCategory.blocks; + } + + @Override + public LInstruction build(LAssembler builder){ + return new ControlI(type, builder.var(target), builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4)); } } @@ -246,7 +358,7 @@ public class LStatements{ }), //sensors new Table(i -> { - for(LSensor sensor : LSensor.all){ + for(LAccess sensor : LAccess.senseable){ i.button(sensor.name(), Styles.cleart, () -> { stype("@" + sensor.name()); hide.run(); @@ -321,31 +433,6 @@ public class LStatements{ } } - @RegisterStatement("enable") - public static class EnableStatement extends LStatement{ - public String target = "result"; - public String value = "0"; - - @Override - public void build(Table table){ - field(table, target, str -> target = str); - - table.add(" -> "); - - field(table, value, str -> value = str); - } - - @Override - public LCategory category(){ - return LCategory.blocks; - } - - @Override - public LInstruction build(LAssembler builder){ - return new EnableI(builder.var(target), builder.var(value)); - } - } - @RegisterStatement("bop") public static class BinaryOpStatement extends LStatement{ public BinaryOp op = BinaryOp.add; @@ -428,31 +515,6 @@ public class LStatements{ } } - @RegisterStatement("print") - public static class PrintStatement extends LStatement{ - public String value = "\"frog\""; - public String target = "result"; - - @Override - public void build(Table table){ - field(table, value, str -> value = str); - - table.add(" to "); - - field(table, target, str -> target = str); - } - - @Override - public LInstruction build(LAssembler builder){ - return new PrintI(builder.var(value), builder.var(target)); - } - - @Override - public LCategory category(){ - return LCategory.control; - } - } - @RegisterStatement("jump") public static class JumpStatement extends LStatement{ public transient StatementElem dest; diff --git a/core/src/mindustry/logic/Senseable.java b/core/src/mindustry/logic/Senseable.java index b07a4d9363..3f9e3798a4 100644 --- a/core/src/mindustry/logic/Senseable.java +++ b/core/src/mindustry/logic/Senseable.java @@ -3,6 +3,6 @@ package mindustry.logic; import mindustry.ctype.*; public interface Senseable{ - double sense(LSensor sensor); + double sense(LAccess sensor); double sense(Content content); } diff --git a/core/src/mindustry/world/blocks/defense/Door.java b/core/src/mindustry/world/blocks/defense/Door.java index af36af68bf..9abb9f02e3 100644 --- a/core/src/mindustry/world/blocks/defense/Door.java +++ b/core/src/mindustry/world/blocks/defense/Door.java @@ -3,6 +3,7 @@ package mindustry.world.blocks.defense; import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; +import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; @@ -12,6 +13,8 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; +import mindustry.logic.*; +import mindustry.world.blocks.defense.Door.*; import static mindustry.Vars.*; @@ -33,6 +36,11 @@ public class Door extends Wall{ Sounds.door.at(base); for(DoorEntity entity : base.chained){ + //skip doors with things in them + if((Units.anyEntities(entity.tile) && !open) || entity.open == open){ + continue; + } + entity.open = open; pathfinder.updateTile(entity.tile()); entity.effect(); @@ -66,6 +74,19 @@ public class Door extends Wall{ } } + @Override + public void control(LAccess type, double p1, double p2, double p3, double p4){ + if(type == LAccess.enabled){ + boolean shouldOpen = !Mathf.zero(p1); + + if(open == shouldOpen || (Units.anyEntities(tile) && !shouldOpen) || !timer(timerToggle, 60f)){ + return; + } + + configureAny(shouldOpen); + } + } + public void effect(){ (open ? closefx : openfx).at(this); } @@ -104,7 +125,7 @@ public class Door extends Wall{ @Override public void tapped(Player player){ - if((Units.anyEntities(tile) && open) || !timer(timerToggle, 30f)){ + if((Units.anyEntities(tile) && open) || !timer(timerToggle, 40f)){ return; } diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 584998ce90..cd2bff3a9d 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -18,6 +18,7 @@ import mindustry.entities.bullet.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -25,9 +26,12 @@ import mindustry.world.consumers.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; -import static mindustry.Vars.tilesize; +import static mindustry.Vars.*; public abstract class Turret extends Block{ + //after being logic-controlled and this amount of time passes, the turret will resume normal AI + public final static float logicControlCooldown = 60 * 2; + public final int timerTarget = timers++; public int targetInterval = 20; @@ -140,8 +144,9 @@ public abstract class Turret extends Block{ public class TurretEntity extends Building implements ControlBlock{ public Seq ammo = new Seq<>(); public int totalAmmo; - public float reload, rotation = 90, recoil, heat; + public float reload, rotation = 90, recoil, heat, logicControlTime = -1; public int shotCounter; + public boolean logicShooting = false; public @Nullable Posc target; public Vec2 targetPos = new Vec2(); public @NonNull BlockUnitc unit = Nulls.blockUnit; @@ -152,11 +157,26 @@ public abstract class Turret extends Block{ unit.tile(this); } + @Override + public void control(LAccess type, double p1, double p2, double p3, double p4){ + if(type == LAccess.shoot && !unit.isPlayer()){ + targetPos.set((float)p1, (float)p2); + logicControlTime = logicControlCooldown; + logicShooting = !Mathf.zero(p3); + } + + super.control(type, p1, p2, p3, p4); + } + @Override public Unit unit(){ return (Unit)unit; } + public boolean logicControlled(){ + return logicControlTime > 0; + } + @Override public void draw(){ Draw.rect(baseRegion, x, y); @@ -184,6 +204,10 @@ public abstract class Turret extends Block{ unit.rotation(rotation); unit.team(team); + if(logicControlTime > 0){ + logicControlTime -= Time.delta; + } + if(hasAmmo()){ if(timer(timerTarget, targetInterval)){ @@ -193,10 +217,11 @@ public abstract class Turret extends Block{ if(validateTarget()){ boolean canShoot = true; - //player behavior - if(isControlled()){ + if(isControlled()){ //player behavior targetPos.set(unit.aimX(), unit.aimY()); canShoot = unit.isShooting(); + }else if(logicControlled()){ //logic behavior + canShoot = logicShooting; }else{ //default AI behavior BulletType type = peekAmmo(); float speed = type.speed; diff --git a/core/src/mindustry/world/blocks/logic/LogicDisplay.java b/core/src/mindustry/world/blocks/logic/LogicDisplay.java index 0c301474aa..a61b6f00c0 100644 --- a/core/src/mindustry/world/blocks/logic/LogicDisplay.java +++ b/core/src/mindustry/world/blocks/logic/LogicDisplay.java @@ -19,8 +19,7 @@ public class LogicDisplay extends Block{ commandRect = 4, commandLineRect = 5, commandPoly = 6, - commandLinePoly = 7, - commandFlush = 8; + commandLinePoly = 7; public int maxSides = 25; @@ -91,7 +90,7 @@ public class LogicDisplay extends Block{ } } - public enum CommandType{ + public enum GraphicsType{ clear, color, stroke, @@ -99,11 +98,9 @@ public class LogicDisplay extends Block{ rect, lineRect, poly, - linePoly, - flush; + linePoly; - public static final CommandType[] all = values(); - public static final CommandType[] allNormal = Seq.select(all, t -> t != flush).toArray(CommandType.class); + public static final GraphicsType[] all = values(); } @Struct diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java index b0640e12d3..2954c1cd26 100644 --- a/core/src/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java @@ -109,8 +109,8 @@ public class NuclearReactor extends PowerGenerator{ } @Override - public double sense(LSensor sensor){ - if(sensor == LSensor.heat) return heat; + public double sense(LAccess sensor){ + if(sensor == LAccess.heat) return heat; return super.sense(sensor); }