diff --git a/annotations/src/main/java/mindustry/annotations/misc/NodeSlotProcessor.java b/annotations/src/main/java/mindustry/annotations/misc/NodeSlotProcessor.java deleted file mode 100644 index 6a1d0eefa6..0000000000 --- a/annotations/src/main/java/mindustry/annotations/misc/NodeSlotProcessor.java +++ /dev/null @@ -1,79 +0,0 @@ -package mindustry.annotations.misc; - -import arc.struct.*; -import arc.util.*; -import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.*; -import mindustry.annotations.*; -import mindustry.annotations.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -@SupportedAnnotationTypes("mindustry.annotations.Annotations.Slot") -public class NodeSlotProcessor extends BaseProcessor{ - - @Override - public void process(RoundEnvironment env) throws Exception{ - TypeSpec.Builder slotClass = TypeSpec.classBuilder("LogicSlotMap") - .addModifiers(Modifier.PUBLIC); - - ObjectMap> fields = new ObjectMap<>(); - for(Svar var : fields(Slot.class)){ - String type = var.mirror().toString(); - - boolean overrideInput = var.annotation(Slot.class).input(); - boolean output = (type.contains("SetObj") || type.contains("SetNum") || type.contains("Runnable")) && !overrideInput; - - String objType = output ? - type.contains("SetNum") ? "double" : - type.contains("SetObj") ? ((DeclaredType)var.mirror()).getTypeArguments().get(0).toString() : - type : type; - - String dataType = objType.equals("double") ? "number" : - objType.contains("Content") ? "content" : - objType.equals("mindustry.gen.Building") ? "building" : - objType.equals("mindustry.gen.Unit") ? "unit" : - objType.equals("java.lang.Void") || objType.equals("java.lang.Runnable") ? "control" : - objType.equals("java.lang.String") ? "string" : - "<>"; - - if(dataType.equals("<>")) err("Unknown logic node type: " + objType, var); - - boolean numeric = dataType.equals("number"); - - String name = Strings.capitalize(var.name()); - - String lambda = output ? - "(" + var.enclosingType() + " node, " + objType + " val__) -> node." + var.name() + (objType.contains("Runnable") ? ".run()" : ".set(val__)") : - "(" + var.enclosingType() + " node, " + objType + " val__) -> node." + var.name() + " = val__"; - - //NodeSlot(String name, boolean input, DataType type, NumOutput numOutput, ObjOutput setObject) - String constructed = Strings.format( - "new mindustry.logic.LogicNode.NodeSlot(\"@\", @, mindustry.logic.LogicNode.DataType.@, @, @)", - name, - !output, - dataType, - numeric ? lambda : "null", - !numeric ? lambda : "null" - ); - - fields.get(var.enclosingType(), Seq::new).add(constructed); - } - - slotClass.addField(FieldSpec.builder( - ParameterizedTypeName.get(ClassName.get(ObjectMap.class), - TypeName.get(Class.class), - TypeName.OBJECT), //screw type safety, I don't care anymore - "map", Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC).initializer("new ObjectMap<>()").build()); - - - CodeBlock.Builder code = CodeBlock.builder(); - fields.each((type, inits) -> code.addStatement("map.put($L.class, new mindustry.logic.LogicNode.NodeSlot[]{$L})", type.toString(), inits.toString(","))); - - slotClass.addStaticBlock(code.build()); - - write(slotClass); - } -} diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index aad55491b9..17683467c9 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1502,7 +1502,7 @@ public class Blocks implements ContentList{ health = 160 * size * size; rotateSpeed = 10; - consumes.power(3f); + consumes.powerCond(3f, (TractorBeamEntity e) -> e.target != null); }}; swarmer = new ItemTurret("swarmer"){{ diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index bdf5337f18..817c912bc7 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -24,7 +24,7 @@ import mindustry.editor.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.logic2.LDialog; +import mindustry.logic.LDialog; import mindustry.ui.*; import mindustry.ui.dialogs.*; import mindustry.ui.fragments.*; diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 38482fd441..360465fb38 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -54,6 +54,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, transient boolean updateFlow; transient byte dump; transient int rotation; + transient boolean enabled = true; PowerModule power; ItemModule items; diff --git a/core/src/mindustry/logic/BinaryOp.java b/core/src/mindustry/logic/BinaryOp.java index 85e4586f4d..c993697a5e 100644 --- a/core/src/mindustry/logic/BinaryOp.java +++ b/core/src/mindustry/logic/BinaryOp.java @@ -6,7 +6,7 @@ public enum BinaryOp{ mul("*", (a, b) -> a * b), div("/", (a, b) -> a / b), mod("%", (a, b) -> a % b), - equal("=", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0), + equal("==", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0), lessThan("<", (a, b) -> a < b ? 1 : 0), lessThanEq("<=", (a, b) -> a <= b ? 1 : 0), greaterThan(">", (a, b) -> a > b ? 1 : 0), @@ -16,7 +16,9 @@ public enum BinaryOp{ shr("<<", (a, b) -> (int)a << (int)b), or("or", (a, b) -> (int)a | (int)b), and("and", (a, b) -> (int)a & (int)b), - xor("xor", (a, b) -> (int)a ^ (int)b); + xor("xor", (a, b) -> (int)a ^ (int)b), + max("max", Math::max), + min("min", Math::min); public static final BinaryOp[] all = values(); diff --git a/core/src/mindustry/logic/DataType.java b/core/src/mindustry/logic/DataType.java new file mode 100644 index 0000000000..49090d69f6 --- /dev/null +++ b/core/src/mindustry/logic/DataType.java @@ -0,0 +1,24 @@ +package mindustry.logic; + +import arc.graphics.*; +import mindustry.graphics.*; + +/** The types of data a node field can be. */ +public enum DataType{ + /** A double. Used for integer calculations as well. */ + number(Pal.place), + /** Any type of content, e.g. item. */ + content(Color.cyan), + /** A building of a tile. */ + building(Pal.items), + /** A unit on the map. */ + unit(Pal.health), + /** Java string */ + string(Color.royal); + + public final Color color; + + DataType(Color color){ + this.color = color; + } +} \ No newline at end of file diff --git a/core/src/mindustry/logic/LBuilder.java b/core/src/mindustry/logic/LBuilder.java new file mode 100644 index 0000000000..fa9ce105f4 --- /dev/null +++ b/core/src/mindustry/logic/LBuilder.java @@ -0,0 +1,49 @@ +package mindustry.logic; + +import arc.struct.*; + +/** "Compiles" a sequence of statements into instructions. */ +public class LBuilder{ + private int lastVar; + /** Maps names to variable IDs. */ + private ObjectIntMap vars = new ObjectIntMap<>(); + /** Maps variable IDs to their constant value. */ + private IntMap constants = new IntMap<>(); + + public LBuilder(){ + //add default constant variables + putConst("false", 0); + putConst("true", 1); + } + + /** @return a variable ID by name. + * This may be a constant variable referring to a number or object. */ + public int var(String symbol){ + try{ + double value = Double.parseDouble(symbol); + //this creates a hidden const variable with the specified value + String key = "___" + value; + return putConst(key, value); + }catch(NumberFormatException e){ + return putVar(symbol); + } + } + + /** Adds a constant value by name. */ + private int putConst(String name, double value){ + int id = putVar(name); + constants.put(id, value); + return id; + } + + /** Registers a variable name mapping. */ + private int putVar(String name){ + if(vars.containsKey(name)){ + return vars.get(name); + }else{ + int id = lastVar++; + vars.put(name, id); + return id; + } + } +} diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java new file mode 100644 index 0000000000..57ba9624f4 --- /dev/null +++ b/core/src/mindustry/logic/LCanvas.java @@ -0,0 +1,348 @@ +package mindustry.logic; + +import arc.*; +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.input.*; +import arc.math.*; +import arc.math.geom.*; +import arc.scene.*; +import arc.scene.event.*; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.logic.LStatements.*; +import mindustry.ui.*; + +public class LCanvas extends Table{ + private static final Color backgroundCol = Pal.darkMetal.cpy().mul(0.1f), gridCol = Pal.darkMetal.cpy().mul(0.5f); + private Vec2 offset = new Vec2(); + + private DragLayout statements; + private StatementElem dragging; + + public LCanvas(){ + //left(); + + statements = new DragLayout(); + + pane(statements).grow().get().setClip(false); + + add(new LStatements.AssignStatement()); + add(new FetchBuildStatement()); + add(new JumpStatement()); + add(new ToggleStatement()); + add(new LStatements.OpStatement()); + } + + private void drawGrid(){ + Draw.color(backgroundCol); + + Fill.crect(x, y, width, height); + + Draw.color(gridCol); + + float spacing = Scl.scl(50f); + int xbars = (int)(width / spacing) + 2, ybars = (int)(width / spacing) + 2; + float ox = offset.x % spacing, oy = offset.y % spacing; + + Lines.stroke(Scl.scl(3f)); + + for(int i = 0; i < xbars; i++){ + float cx = x + width/2f + (i - xbars/2) * spacing + ox; + Lines.line(cx, y, cx, y + height); + } + + for(int i = 0; i < ybars; i++){ + float cy = y + height/2f + (i - ybars/2) * spacing + oy; + Lines.line(0, cy, x + width, cy); + } + + Draw.reset(); + } + + void add(LStatement statement){ + StatementElem e = new StatementElem(statement); + + statements.addChild(e); + } + + public class DragLayout extends WidgetGroup{ + float margin = 4f; + float space = 10f, width = 400f; + Seq seq = new Seq<>(); + int insertPosition = 0; + + @Override + public void layout(){ + float cy = 0; + seq.clear(); + + //layout everything normally + for(int i = 0; i < getChildren().size; i++){ + Element e = getChildren().get(i); + + //ignore the dragged element + if(dragging == e) continue; + + e.setSize(width - margin * 2f, e.getPrefHeight()); + e.setPosition(x + margin, height + y - margin - cy, Align.topLeft); + + cy += e.getPrefHeight() + space; + seq.add(e); + } + + //insert the dragged element if necessary + if(dragging != null){ + //find real position of dragged element top + float realY = dragging.getY(Align.top) + dragging.translation.y; + + insertPosition = 0; + + for(int i = 0; i < seq.size; i++){ + Element cur = seq.get(i); + //find fit point + if(realY < cur.y && (i == seq.size - 1 || realY > seq.get(i + 1).y)){ + insertPosition = i + 1; + break; + } + } + + float shiftAmount = dragging.getHeight() + space; + + //shift elements below insertion point down + for(int i = insertPosition; i < seq.size; i++){ + seq.get(i).y -= shiftAmount; + } + } + } + + @Override + public void draw(){ + + //draw selection box indicating placement position + if(dragging != null && insertPosition <= seq.size){ + float shiftAmount = dragging.getHeight(); + float lastX = x + margin; + float lastY = insertPosition == 0 ? height + y - margin : seq.get(insertPosition - 1).y - space; + + Tex.pane.draw(lastX, lastY - shiftAmount, width - margin*2f, dragging.getHeight()); + } + + super.draw(); + } + + void finishLayout(){ + if(dragging != null){ + //reset translation first + for(Element child : getChildren()){ + child.setTranslation(0, 0); + } + clearChildren(); + + //reorder things + for(int i = 0; i <= insertPosition - 1 && i < seq.size; i++){ + addChild(seq.get(i)); + } + + addChild(dragging); + + for(int i = insertPosition; i < seq.size; i++){ + addChild(seq.get(i)); + } + + dragging = null; + } + + layout(); + } + } + + public class StatementElem extends Table{ + LStatement st; + + public StatementElem(LStatement st){ + this.st = st; + + background(Tex.whitePane); + setColor(st.category().color); + margin(0f); + touchable = Touchable.enabled; + + table(Tex.whiteui, t -> { + t.color.set(color); + t.addListener(new HandCursorListener()); + + t.margin(6f); + t.touchable = Touchable.enabled; + + t.add(st.name()).style(Styles.outlineLabel).color(color).padRight(8); + t.add().growX(); + t.button(Icon.cancel, Styles.onlyi, () -> { + remove(); + dragging = null; + statements.layout(); + }); + + t.addListener(new InputListener(){ + float lastx, lasty; + + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ + Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); + lastx = v.x; + lasty = v.y; + dragging = StatementElem.this; + toFront(); + statements.layout(); + return true; + } + + @Override + public void touchDragged(InputEvent event, float x, float y, int pointer){ + Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); + + translation.add(v.x - lastx, v.y - lasty); + lastx = v.x; + lasty = v.y; + + statements.layout(); + } + + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){ + statements.finishLayout(); + } + }); + }).growX(); + + row(); + + table(t -> { + t.left(); + t.marginLeft(4); + t.setColor(color); + st.build(t); + }).pad(4).padTop(2).left().grow(); + + marginBottom(7); + } + + @Override + public void draw(){ + float pad = 5f; + Fill.dropShadow(x + width/2f, y + height/2f, width + pad, height + pad, 10f, 0.9f); + + Draw.color(0, 0, 0, 0.3f); + Fill.crect(x, y, width, height); + Draw.reset(); + + super.draw(); + } + } + + public static class JumpButton extends ImageButton{ + StatementElem to; + boolean selecting; + float mx, my; + + public JumpButton(Color color, Cons setter){ + super(Tex.logicNode, Styles.colori); + + getStyle().imageUpColor = color; + + addListener(new InputListener(){ + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode code){ + selecting = true; + setter.get(to = null); + mx = x; + my = y; + return true; + } + + @Override + public void touchDragged(InputEvent event, float x, float y, int pointer){ + mx = x; + my = y; + } + + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode code){ + localToStageCoordinates(Tmp.v1.set(x, y)); + StatementElem elem = hovered(); + + if(elem != null && !isDescendantOf(elem)){ + to = elem; + }else{ + to = null; + } + setter.get(to); + selecting = false; + } + }); + + update(() -> { + if(to != null && to.parent == null){ + setter.get(to = null); + } + }); + } + + @Override + public void draw(){ + super.draw(); + Element hover = to == null && selecting ? hovered() : to; + float tx = 0, ty = 0; + boolean draw = false; + + if(hover != null){ + tx = hover.getX(Align.right) + hover.translation.x; + ty = hover.getY(Align.right) + hover.translation.y; + draw = true; + }else if(selecting){ + tx = x + mx; + ty = y + my; + draw = true; + } + + if(draw){ + drawCurve(x + width/2f, y + height/2f, tx, ty, color); + + float s = width; + Tex.logicNode.draw(tx + s*0.75f, ty - s/2f, -s, s); + } + } + + StatementElem hovered(){ + Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true); + if(e != null){ + while(e != null && !(e instanceof StatementElem)){ + e = e.parent; + } + } + if(e == null || isDescendantOf(e)) return null; + return (StatementElem)e; + } + + void drawCurve(float x, float y, float x2, float y2, Color color){ + Lines.stroke(4f, color); + + float dist = 100f; + + Lines.curve( + x, y, + x + dist, y, + x2 + dist, y2, + x2, y2, + Math.max(20, (int)(Mathf.dst(x, y, x2, y2) / 5)) + ); + + Draw.reset(); + } + } +} diff --git a/core/src/mindustry/logic/LCategory.java b/core/src/mindustry/logic/LCategory.java new file mode 100644 index 0000000000..52ff405f04 --- /dev/null +++ b/core/src/mindustry/logic/LCategory.java @@ -0,0 +1,16 @@ +package mindustry.logic; + +import arc.graphics.*; +import mindustry.graphics.*; + +public enum LCategory{ + blocks(Pal.accentBack), + control(Color.cyan.cpy().shiftSaturation(-0.6f).mul(0.7f)), + operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f)); + + public final Color color; + + LCategory(Color color){ + this.color = color; + } +} diff --git a/core/src/mindustry/logic2/LDialog.java b/core/src/mindustry/logic/LDialog.java similarity index 85% rename from core/src/mindustry/logic2/LDialog.java rename to core/src/mindustry/logic/LDialog.java index ba4f7ce827..d16007e355 100644 --- a/core/src/mindustry/logic2/LDialog.java +++ b/core/src/mindustry/logic/LDialog.java @@ -1,10 +1,10 @@ -package mindustry.logic2; +package mindustry.logic; import arc.scene.ui.layout.*; import mindustry.ui.dialogs.*; public class LDialog extends BaseDialog{ - LCanvas canvas; + mindustry.logic.LCanvas canvas; public LDialog(){ super("logic"); diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java new file mode 100644 index 0000000000..ea2f763fef --- /dev/null +++ b/core/src/mindustry/logic/LExecutor.java @@ -0,0 +1,179 @@ +package mindustry.logic; + +import arc.util.ArcAnnotate.*; +import mindustry.*; +import mindustry.gen.*; + +public class LExecutor{ + LInstruction[] instructions; + int counter; + + //values of all the variables + Var[] vars; + + /** Runs all the instructions at once. Debugging only. */ + public void runAll(){ + counter = 0; + + while(counter < instructions.length){ + instructions[counter++].run(this); + } + } + + @Nullable Building building(int index){ + Object o = vars[index].objval; + return o == null && o instanceof Building ? (Building)o : null; + } + + boolean bool(int index){ + Var v = vars[index]; + return v.isobj ? v.objval != null : Math.abs(v.numval) < 0.0001; + } + + double num(int index){ + Var v = vars[index]; + return v.isobj ? 0 : v.numval; + } + + int numi(int index){ + return (int)num(index); + } + + void setnum(int index, double value){ + Var v = vars[index]; + if(v.constant) return; + v.numval = value; + v.objval = null; + v.isobj = false; + } + + void setobj(int index, Object value){ + Var v = vars[index]; + if(v.constant) return; + v.objval = value; + v.isobj = true; + } + + static class Var{ + boolean isobj, constant; + + Object objval; + double numval; + } + + //region instruction types + + public interface LInstruction{ + void run(LExecutor exec); + } + + /** Enables/disables a building. */ + public static class ToggleI implements LInstruction{ + public int target, value; + + public ToggleI(int target, int value){ + this.target = target; + this.value = value; + } + + @Override + public void run(LExecutor exec){ + Building b = exec.building(target); + if(b != null) b.enabled = exec.bool(value); + } + } + + public static class SenseI implements LInstruction{ + public int from, to; + + @Override + public void run(LExecutor exec){ + + } + } + + public static class AssignI implements LInstruction{ + public int from, to; + + public AssignI(int from, int to){ + this.from = from; + this.to = to; + } + + @Override + public void run(LExecutor exec){ + Var v = exec.vars[to]; + Var f = exec.vars[from]; + + //TODO error out when the from-value is a constant + if(!v.constant){ + if(f.isobj){ + v.objval = f.objval; + v.isobj = true; + }else{ + v.numval = f.numval; + v.isobj = false; + } + } + } + } + + public static class BinaryOpI implements LInstruction{ + public mindustry.logic.BinaryOp op; + public int a, b, dest; + + public BinaryOpI(BinaryOp op, int a, int b, int dest){ + this.op = op; + this.a = a; + this.b = b; + this.dest = dest; + } + + @Override + public void run(LExecutor exec){ + exec.setnum(dest, op.function.get(exec.num(a), exec.num(b))); + } + } + + public static class EndI implements LInstruction{ + + @Override + public void run(LExecutor exec){ + exec.counter = exec.instructions.length; + } + } + + public static class JumpI implements LInstruction{ + public int cond, to; + + public JumpI(int cond, int to){ + this.cond = cond; + this.to = to; + } + + @Override + public void run(LExecutor exec){ + if(to != -1 && exec.bool(cond)){ + exec.counter = to; + } + } + } + + public static class FetchBuildI implements LInstruction{ + public int dest; + public int x, y; + + public FetchBuildI(int dest, int x, int y){ + this.dest = dest; + this.x = x; + this.y = y; + } + + @Override + public void run(LExecutor exec){ + exec.setobj(dest, Vars.world.build(exec.numi(x), exec.numi(y))); + } + } + + //endregion +} diff --git a/core/src/mindustry/logic/LStatement.java b/core/src/mindustry/logic/LStatement.java new file mode 100644 index 0000000000..a19e687211 --- /dev/null +++ b/core/src/mindustry/logic/LStatement.java @@ -0,0 +1,15 @@ +package mindustry.logic; + +import arc.scene.ui.layout.*; + +/** A statement is an intermediate representation of an instruction, to be used in UI. */ +public abstract class LStatement{ + + public abstract void build(Table table); + public abstract LCategory category(); + public abstract LExecutor.LInstruction build(LBuilder builder); + + public String name(){ + return getClass().getSimpleName().replace("Statement", ""); + } +} diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java new file mode 100644 index 0000000000..b260144a58 --- /dev/null +++ b/core/src/mindustry/logic/LStatements.java @@ -0,0 +1,171 @@ +package mindustry.logic; + +import arc.graphics.*; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import mindustry.logic.LExecutor.*; +import mindustry.logic.LCanvas.*; +import mindustry.ui.*; + +public class LStatements{ + + public static class AssignStatement extends LStatement{ + public String to = "result"; + public String from = "0"; + + @Override + public void build(Table table){ + table.field(to, Styles.nodeField, str -> to = str) + .size(100f, 40f).pad(2f).color(table.color); + + table.add(" = "); + + table.field(from, Styles.nodeField, str -> from = str) + .size(100f, 40f).pad(2f).color(table.color); + } + + @Override + public LCategory category(){ + return LCategory.operations; + } + + @Override + public LExecutor.LInstruction build(LBuilder builder){ + //TODO internal consts need to start with ___ and not be assignable to + return new LExecutor.AssignI(builder.var(from), builder.var(to)); + } + } + + public static class ToggleStatement extends LStatement{ + public String target = "result"; + public String value = "0"; + + @Override + public void build(Table table){ + table.field(target, Styles.nodeField, str -> target = str) + .size(100f, 40f).pad(2f).color(table.color); + + table.add(" -> "); + + table.field(value, Styles.nodeField, str -> value = str) + .size(100f, 40f).pad(2f).color(table.color); + } + + @Override + public LCategory category(){ + return LCategory.operations; + } + + @Override + public LExecutor.LInstruction build(LBuilder builder){ + return new LExecutor.ToggleI(builder.var(target), builder.var(value)); + } + } + + public static class OpStatement extends LStatement{ + public mindustry.logic.BinaryOp op = mindustry.logic.BinaryOp.add; + public String a = "a", b = "b", dest = "result"; + + @Override + public void build(Table table){ + table.field(dest, Styles.nodeField, str -> dest = str) + .size(100f, 40f).pad(2f).color(table.color); + + table.add(" = "); + + table.field(a, Styles.nodeField, str -> a = str) + .size(90f, 40f).pad(2f).color(table.color); + + + TextButton[] button = {null}; + button[0] = table.button(op.symbol, Styles.cleart, () -> { + op = mindustry.logic.BinaryOp.all[(op.ordinal() + 1) % BinaryOp.all.length]; + button[0].setText(op.symbol); + }).size(50f, 30f).pad(4f).get(); + + table.field(b, Styles.nodeField, str -> b = str) + .size(90f, 40f).pad(2f).color(table.color); + } + + @Override + public LInstruction build(LBuilder builder){ + return new BinaryOpI(op,builder.var(a), builder.var(b), builder.var(dest)); + } + + @Override + public LCategory category(){ + return LCategory.operations; + } + } + + public static class EndStatement extends LStatement{ + @Override + public void build(Table table){ + + } + + @Override + public LInstruction build(LBuilder builder){ + return new EndI(); + } + + @Override + public LCategory category(){ + return LCategory.control; + } + } + + public static class JumpStatement extends LStatement{ + public StatementElem dest; + public String condition = " true"; + + @Override + public void build(Table table){ + table.add("if ").padLeft(6); + table.field(condition, Styles.nodeField, str -> condition = str) + .size(100f, 40f).pad(2f).color(table.color); + table.add().growX(); + table.add(new JumpButton(Color.white, s -> dest = s)).size(30).right().padRight(-17); + } + + @Override + public LInstruction build(LBuilder builder){ + return new JumpI(builder.var(condition), dest == null ? -1 : dest.parent.getChildren().indexOf(dest)); + } + + @Override + public LCategory category(){ + return LCategory.control; + } + } + + public static class FetchBuildStatement extends LStatement{ + public String x = "0", y = "0", dest = "result"; + + @Override + public void build(Table table){ + table.field(dest, Styles.nodeField, str -> dest = str) + .size(100f, 40f).pad(2f).color(table.color); + + table.add(" = "); + + table.field(x, Styles.nodeField, str -> x = str) + .size(90f, 40f).pad(2f).color(table.color); + + table.add(", "); + + table.field(y, Styles.nodeField, str -> y = str) + .size(90f, 40f).pad(2f).color(table.color); + } + + @Override + public LExecutor.LInstruction build(LBuilder builder){ + return new FetchBuildI(builder.var(dest), builder.var(x), builder.var(y)); + } + + @Override + public LCategory category(){ + return LCategory.blocks; + } + } +} diff --git a/core/src/mindustry/logic/LogicCanvas.java b/core/src/mindustry/logic/LogicCanvas.java deleted file mode 100644 index 6e3e63d001..0000000000 --- a/core/src/mindustry/logic/LogicCanvas.java +++ /dev/null @@ -1,388 +0,0 @@ -package mindustry.logic; - -import arc.*; -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.input.*; -import arc.math.*; -import arc.math.geom.*; -import arc.scene.*; -import arc.scene.event.*; -import arc.scene.ui.*; -import arc.scene.ui.layout.*; -import arc.util.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.io.*; -import mindustry.logic.LogicNode.*; -import mindustry.logic.LogicNodes.*; -import mindustry.logic.SavedLogic.*; -import mindustry.ui.*; - -public class LogicCanvas extends WidgetGroup{ - private static final Color backgroundCol = Pal.darkMetal.cpy().mul(0.1f), gridCol = Pal.darkMetal.cpy().mul(0.5f); - - private Element selected; - private Element entered; - private Vec2 offset = new Vec2(); - - { - addListener(new InputListener(){ - float lastX, lastY; - - @Override - public void touchDragged(InputEvent event, float mx, float my, int pointer){ - if(Core.app.isMobile() && pointer != 0) return; - - float dx = mx - lastX, dy = my - lastY; - offset.add(dx, dy); - - for(Element e : getChildren()){ - e.moveBy(dx, dy); - } - - lastX = mx; - lastY = my; - } - - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ - if((Core.app.isMobile() && pointer != 0) || (Core.app.isDesktop() && button != KeyCode.mouseMiddle)) return false; - - lastX = x; - lastY = y; - return true; - } - }); - - //TODO debug stuff - add(new BinaryOpNode()); - add(new BinaryOpNode()); - add(new BinaryOpNode()); - add(new NumberNode()); - add(new NumberNode()); - add(new NumberNode()); - add(new ConditionNode()); - add(new ConditionNode()); - add(new SignalNode()); - add(new SequenceNode()); - - Log.info(JsonIO.print(JsonIO.write(save()))); - } - - private void add(LogicNode node){ - NodeElement e = new NodeElement(node); - e.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f); - addChild(e); - e.pack(); - } - - public SavedLogic save(){ - - //convert elements to saved nodes for writing to JSON - return new SavedLogic(getChildren().as().map(e -> { - SavedNode node = new SavedNode(); - node.state = e.node; - node.x = e.x; - node.y = e.y; - node.connections = new SavedConnection[e.slots.length]; - - for(int i = 0; i < e.slots.length; i++){ - SavedConnection con = (node.connections[i] = new SavedConnection()); - SlotElement slot = e.slots[i]; - - if(slot.connection != null){ - SlotElement to = slot.connection; - - con.node = getChildren().indexOf(to.node); - con.slot = Structs.indexOf(to.node.slots, to); - }else{ - con.node = -1; - } - } - - return node; - }).toArray(SavedNode.class)); - } - - public void load(SavedLogic state){ - clear(); - - //add nodes as children first to make sure they can be accessed. - for(SavedNode node : state.nodes){ - NodeElement elem = new NodeElement(node.state); - elem.setPosition(node.x, node.y); - addChild(elem); - } - - //assign connection data - for(int i = 0; i < state.nodes.length; i++){ - SavedNode node = state.nodes[i]; - NodeElement elem = (NodeElement)getChildren().get(i); - - for(int j = 0; j < node.connections.length; j++){ - SavedConnection con = node.connections[j]; - if(con.node >= 0 && con.node < state.nodes.length){ - SlotElement slot = elem.slots[j]; - slot.connection = ((NodeElement)getChildren().get(con.node)).slots[con.slot]; - } - } - - elem.pack(); - } - } - - @Override - public void draw(){ - Draw.color(backgroundCol); - - Fill.crect(x, y, width, height); - - Draw.color(gridCol); - - float spacing = Scl.scl(50f); - int xbars = (int)(width / spacing) + 2, ybars = (int)(width / spacing) + 2; - float ox = offset.x % spacing, oy = offset.y % spacing; - - Lines.stroke(Scl.scl(3f)); - - for(int i = 0; i < xbars; i++){ - float cx = x + width/2f + (i - xbars/2) * spacing + ox; - Lines.line(cx, y, cx, y + height); - } - - for(int i = 0; i < ybars; i++){ - float cy = y + height/2f + (i - ybars/2) * spacing + oy; - Lines.line(0, cy, x + width, cy); - } - - Draw.reset(); - - super.draw(); - - for(Element e : getChildren()){ - if(e instanceof NodeElement){ - NodeElement l = (NodeElement)e; - - for(SlotElement field : l.slots){ - field.drawConnection(); - } - } - } - - if(selected != null){ - SlotElement field = (SlotElement)selected.userObject; - Vec2 dest = selected.localToStageCoordinates(Tmp.v1.set(selected.getWidth()/2f, selected.getHeight()/2f)); - Vec2 mouse = Core.input.mouse(); - drawCurve(dest.x, dest.y, mouse.x, mouse.y, field.color); - } - } - - void drawCurve(float x, float y, float x2, float y2, Color color){ - Lines.stroke(4f, color); - - float dist = Math.abs(x - x2)/2f; - - Lines.curve( - x, y, - x + dist, y, - x2 - dist, y2, - x2, y2, - Math.max(3, (int)(Mathf.dst(x, y, x2, y2) / 5)) - ); - - Draw.reset(); - } - - class NodeElement extends Table{ - final LogicNode node; - SlotElement[] slots; - Table slotTable; - - NodeElement(LogicNode node){ - this.node = node; - - background(Tex.whitePane); - setColor(node.category().color); - margin(0f); - - table(Tex.whiteui, t -> { - t.update(() -> { - t.setColor(color); - }); - - t.margin(8f); - t.touchable = Touchable.enabled; - - t.add(node.name()).style(Styles.outlineLabel).color(color).padRight(8); - t.add().growX(); - t.button(Icon.cancel, Styles.onlyi, () -> { - //TODO disconnect things - remove(); - }); - t.addListener(new InputListener(){ - float lastx, lasty; - - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ - Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); - lastx = v.x; - lasty = v.y; - toFront(); - return true; - } - - @Override - public void touchDragged(InputEvent event, float x, float y, int pointer){ - Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); - - moveBy(v.x - lastx, v.y - lasty); - lastx = v.x; - lasty = v.y; - } - }); - }).growX().padBottom(6); - - row(); - - node.build(this); - - row(); - - table(t -> slotTable = t).fill(); - - rebuildSlots(); - - marginBottom(7); - } - - void rebuildSlots(){ - slotTable.clear(); - slotTable.defaults().height(30); - - NodeSlot[] nslots = node.slots(); - - this.slots = new SlotElement[nslots.length]; - for(int i = 0; i < nslots.length; i++){ - this.slots[i] = new SlotElement(this, nslots[i]); - } - - for(SlotElement field : slots){ - slotTable.add(field).growX().align(field.slot.input ? Align.left : Align.right); - slotTable.row(); - } - - pack(); - } - - @Override - public void draw(){ - float pad = 10f; - Fill.dropShadow(x + width/2f, y + height/2f, width + pad, height + pad, 20f, 0.95f); - - Draw.color(0, 0, 0, 0.3f); - Fill.crect(x, y, width, height); - Draw.reset(); - - super.draw(); - } - } - - class SlotElement extends Table{ - final NodeSlot slot; - final NodeElement node; - - ImageButton button; - SlotElement connection; - - SlotElement(NodeElement node, NodeSlot slot){ - this.slot = slot; - this.node = node; - - setColor(slot.type.color); - - float marg = 24f; - - if(slot.input){ - addIcon(); - left(); - marginRight(marg); - }else{ - right(); - marginLeft(marg); - } - - add(slot.name).padLeft(5).padRight(5).style(Styles.outlineLabel).color(color); - - if(!slot.input){ - addIcon(); - } - } - - void drawConnection(){ - if(connection != null){ - ImageButton cb = connection.button; - Vec2 from = localToStageCoordinates(Tmp.v2.set(button.x + button.getWidth()/2f, button.y + button.getHeight()/2f)); - Vec2 to = cb.localToStageCoordinates(Tmp.v1.set(cb.getWidth()/2f, cb.getHeight()/2f)); - - drawCurve(from.x, from.y, to.x, to.y, color); - } - } - - void addIcon(){ - float s = 30f; - Cell c = button(Tex.logicNode, Styles.colori, () -> { - - }).size(s); - - button = c.get(); - button.userObject = this; - button.getStyle().imageUpColor = color; - - float pad = s/2f - 3f; - - if(slot.input){ - c.padLeft(-pad); - }else{ - c.padRight(-pad); - } - - button.addListener(new InputListener(){ - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode code){ - - if(selected == null && !slot.input){ - selected = button; - return true; - } - - return false; - } - - @Override - public void enter(InputEvent event, float x, float y, int pointer, Element fromActor){ - entered = button; - } - - @Override - public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode code){ - localToStageCoordinates(Tmp.v1.set(x, y)); - Element element = entered; - - if(element != null && element.userObject instanceof SlotElement){ - SlotElement field = (SlotElement)element.userObject; - //make sure inputs are matched to outputs, and that slot types match - if(field != SlotElement.this && field.slot.input != slot.input && field.slot.type == slot.type){ - connection = field; - //field.connection = button; - } - } - - if(selected == button){ - selected = null; - } - } - }); - } - } -} diff --git a/core/src/mindustry/logic/LogicExecutor.java b/core/src/mindustry/logic/LogicExecutor.java deleted file mode 100644 index 263cd8c3ec..0000000000 --- a/core/src/mindustry/logic/LogicExecutor.java +++ /dev/null @@ -1,45 +0,0 @@ -package mindustry.logic; - -import mindustry.logic.LogicNode.*; -import mindustry.logic.SavedLogic.*; - -public class LogicExecutor{ - /** all logical operations to be executed */ - private LogicOp[] ops = {}; - /** current operation index */ - private int index; - - /** Set up executor state based on saved data. */ - public void setup(SavedLogic save){ - LogicNode[] out = new LogicNode[save.nodes.length]; - - //copy over the state so connections can be assigned - for(int i = 0; i < out.length; i++){ - out[i] = save.nodes[i].state; - } - - for(int i = 0; i < out.length; i++){ - LogicNode node = out[i]; - NodeSlot[] slots = node.slots(); - - //connect node's slots to other nodes' slots - for(int j = 0; j < save.nodes[i].connections.length; j++){ - SavedConnection con = save.nodes[i].connections[j]; - NodeSlot slot = slots[j]; - - if(con.node != -1){ - LogicNode other = out[con.node]; - NodeSlot[] otherSlots = other.slots(); - NodeSlot otherSlot = otherSlots[con.slot]; - - //slot.objOutput = (aslot, aobj) -> ((ObjOutput)otherSlot.objOutput).set(other, aobj); - } - } - } - } - - /** A single logical statement. */ - static class LogicOp{ - - } -} diff --git a/core/src/mindustry/logic/LogicNode.java b/core/src/mindustry/logic/LogicNode.java deleted file mode 100644 index f3fea56ad0..0000000000 --- a/core/src/mindustry/logic/LogicNode.java +++ /dev/null @@ -1,96 +0,0 @@ -package mindustry.logic; - -import arc.graphics.*; -import arc.scene.ui.layout.*; -import mindustry.gen.*; -import mindustry.graphics.*; - -/** Base class for a type of logic node. */ -public abstract class LogicNode{ - - /** Runs the calculation(s) and sets the output value. */ - public void run(){} - - public NodeSlot[] slots(){ - return (NodeSlot[])LogicSlotMap.map.get(getClass()); - } - - public abstract NodeCategory category(); - - public void build(Table table){} - - public String name(){ - return getClass().getSimpleName().replace("Node", ""); - } - - /** A field for a node, either an input or output. */ - public static class NodeSlot{ - /** The slot's display name. */ - public final String name; - /** If true this field accepts values. */ - public final boolean input; - /** The type of data accepted or returned by this slot. */ - public final DataType type; - - public final NumOutput numOutput; - public final ObjOutput objOutput; - - public NodeSlot(String name, boolean input, DataType type, NumOutput numOutput, ObjOutput objOutput){ - this.name = name; - this.input = input; - this.type = type; - this.numOutput = numOutput; - this.objOutput = objOutput; - } - } - - public interface NumOutput{ - void set(N node, double val); - } - - public interface ObjOutput{ - void set(N node, T val); - } - - public interface SetNum{ - void set(double val); - } - - public interface SetObj{ - void set(T val); - } - - public enum NodeCategory{ - controlFlow(Pal.accentBack), - operations(Pal.place.cpy().shiftSaturation(-0.4f).mul(0.7f)); - - public final Color color; - - NodeCategory(Color color){ - this.color = color; - } - } - - /** The types of data a node field can be. */ - public enum DataType{ - /** A double. Used for integer calculations as well. */ - number(Pal.place), - /** Any type of content, e.g. item. */ - content(Color.cyan), - /** A building of a tile. */ - building(Pal.items), - /** A unit on the map. */ - unit(Pal.health), - /** Control flow (void)*/ - control(Color.white), - /** Java string */ - string(Color.royal); - - public final Color color; - - DataType(Color color){ - this.color = color; - } - } - -} diff --git a/core/src/mindustry/logic/LogicNodes.java b/core/src/mindustry/logic/LogicNodes.java deleted file mode 100644 index a07249ab25..0000000000 --- a/core/src/mindustry/logic/LogicNodes.java +++ /dev/null @@ -1,123 +0,0 @@ -package mindustry.logic; - -import arc.graphics.*; -import arc.scene.ui.*; -import arc.scene.ui.layout.*; -import arc.util.*; -import mindustry.annotations.Annotations.*; -import mindustry.ui.*; - -public class LogicNodes{ - public static class BinaryOpNode extends LogicNode{ - public BinaryOp op = BinaryOp.add; - @Slot - public double a, b; - @Slot - public transient SetNum result = val -> {}; - - @Override - public void build(Table table){ - //TODO replace with dropdown menu - TextButton[] button = {null}; - button[0] = table.button(op.symbol, Styles.cleart, () -> { - op = BinaryOp.all[(op.ordinal() + 1) % BinaryOp.all.length]; - button[0].setText(op.symbol); - }).size(100f, 40f).pad(2f).get(); - } - - @Override - public void run(){ - result.set(op.function.get(a, b)); - } - - @Override - public NodeCategory category(){ - return NodeCategory.operations; - } - } - - public static class ConditionNode extends LogicNode{ - @Slot(input = true) - public transient Runnable input = this::run; - @Slot - public double condition; - @Slot - public transient Runnable yes, no; - - @Override - public void run(){ - if(condition > 0){ - yes.run(); - }else{ - no.run(); - } - } - - @Override - public NodeCategory category(){ - return NodeCategory.controlFlow; - } - } - - public static class NumberNode extends LogicNode{ - @Slot - public transient SetNum value; - public double var; - - @Override - public void build(Table table){ - table.field(var + "", Styles.nodeField, str -> var = parseDouble(str)) - .size(100f, 40f).pad(2f).color(table.color) - .update(f -> f.setColor(f.isValid() ? table.color : Color.white)); - } - - @Override - public void run(){ - value.set(var); - } - - @Override - public NodeCategory category(){ - return NodeCategory.controlFlow; - } - - static double parseDouble(String s){ - return s.equals("yes") || s.equals("true") ? 1 : - s.equals("no") || s.equals("false") ? 0 : - Strings.parseDouble(s, 0); - } - } - - public static class SequenceNode extends LogicNode{ - @Slot(input = true) - public transient Runnable input = this::run; - @Slot - public transient Runnable first, second; - - @Override - public void run(){ - first.run(); - second.run(); - } - - @Override - public NodeCategory category(){ - return NodeCategory.controlFlow; - } - } - - public static class SignalNode extends LogicNode{ - @Slot - public transient Runnable run; - - @Override - public void run(){ - run.run(); - } - - @Override - public NodeCategory category(){ - return NodeCategory.controlFlow; - } - } -} diff --git a/core/src/mindustry/logic/SavedLogic.java b/core/src/mindustry/logic/SavedLogic.java deleted file mode 100644 index 66e41b8d41..0000000000 --- a/core/src/mindustry/logic/SavedLogic.java +++ /dev/null @@ -1,26 +0,0 @@ -package mindustry.logic; - -/** The saved state of a logic board. */ -public class SavedLogic{ - public SavedNode[] nodes; - - public SavedLogic(SavedNode[] nodes){ - this.nodes = nodes; - } - - public static class SavedNode{ - /** Uninitialized state containing only relevant configuration. */ - public LogicNode state; - /** Connections of this node. */ - public SavedConnection[] connections; - /** x/y positions of the bottom left corner of the node */ - public float x, y; - } - - public static class SavedConnection{ - /** Node ID (in the array) that is being connected to. -1 means no connection */ - public int node; - /** Slot number in the node */ - public int slot; - } -} diff --git a/core/src/mindustry/logic2/LCanvas.java b/core/src/mindustry/logic2/LCanvas.java deleted file mode 100644 index da299668f1..0000000000 --- a/core/src/mindustry/logic2/LCanvas.java +++ /dev/null @@ -1,103 +0,0 @@ -package mindustry.logic2; - -import arc.input.*; -import arc.math.geom.*; -import arc.scene.event.*; -import arc.scene.ui.layout.*; -import arc.struct.*; -import arc.util.*; -import mindustry.gen.*; -import mindustry.logic2.LStatements.*; -import mindustry.ui.*; - -public class LCanvas extends Table{ - - private Table statements; - private Seq elems = new Seq<>(); - - public LCanvas(){ - //left(); - - pane(t -> { - t.setClip(false); - statements = t; - statements.defaults().width(300f).pad(4f); - t.marginRight(1); - }).growY().get().setClip(false); - - add(new AssignStatement()); - add(new AssignStatement()); - add(new OpStatement()); - } - - void add(LStatement statement){ - StatementElem e = new StatementElem(statement); - elems.add(e); - - statements.add(e); - statements.row(); - } - - public class StatementElem extends Table{ - LStatement st; - - public StatementElem(LStatement st){ - this.st = st; - - background(Tex.whitePane); - setColor(st.category().color); - margin(0f); - - table(Tex.whiteui, t -> { - t.color.set(color); - - t.margin(8f); - t.touchable = Touchable.enabled; - - t.add(st.name()).style(Styles.outlineLabel).color(color).padRight(8); - t.add().growX(); - t.button(Icon.cancel, Styles.onlyi, () -> { - //TODO disconnect things - remove(); - elems.remove(this); - }); - - t.addListener(new InputListener(){ - float lastx, lasty; - - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ - Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); - lastx = v.x; - lasty = v.y; - toFront(); - return true; - } - - @Override - public void touchDragged(InputEvent event, float x, float y, int pointer){ - Vec2 v = localToStageCoordinates(Tmp.v1.set(x, y)); - - translation.add(v.x - lastx, v.y - lasty); - lastx = v.x; - lasty = v.y; - } - - @Override - public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){ - translation.setZero(); - } - }); - }).growX().padBottom(6); - - row(); - - table(t -> { - t.setColor(color); - st.build(t); - }).pad(8).padTop(2); - - marginBottom(7); - } - } -} diff --git a/core/src/mindustry/logic2/LCategory.java b/core/src/mindustry/logic2/LCategory.java deleted file mode 100644 index a51d6d9efe..0000000000 --- a/core/src/mindustry/logic2/LCategory.java +++ /dev/null @@ -1,15 +0,0 @@ -package mindustry.logic2; - -import arc.graphics.*; -import mindustry.graphics.*; - -public enum LCategory{ - control(Pal.accentBack), - operations(Pal.place.cpy().shiftSaturation(-0.4f).mul(0.7f)); - - public final Color color; - - LCategory(Color color){ - this.color = color; - } -} diff --git a/core/src/mindustry/logic2/LExecutor.java b/core/src/mindustry/logic2/LExecutor.java deleted file mode 100644 index f37cb00e1d..0000000000 --- a/core/src/mindustry/logic2/LExecutor.java +++ /dev/null @@ -1,6 +0,0 @@ -package mindustry.logic2; - -public class LExecutor{ - LStatement[] statements; - int counter; -} diff --git a/core/src/mindustry/logic2/LStatement.java b/core/src/mindustry/logic2/LStatement.java deleted file mode 100644 index d6f15c3b22..0000000000 --- a/core/src/mindustry/logic2/LStatement.java +++ /dev/null @@ -1,14 +0,0 @@ -package mindustry.logic2; - -import arc.scene.ui.layout.*; - -public abstract class LStatement{ - - public abstract void run(LExecutor exec); - public abstract void build(Table table); - public abstract LCategory category(); - - public String name(){ - return getClass().getSimpleName(); - } -} diff --git a/core/src/mindustry/logic2/LStatements.java b/core/src/mindustry/logic2/LStatements.java deleted file mode 100644 index d1a1b000f5..0000000000 --- a/core/src/mindustry/logic2/LStatements.java +++ /dev/null @@ -1,60 +0,0 @@ -package mindustry.logic2; - -import arc.scene.ui.layout.*; -import arc.util.*; -import mindustry.logic.*; -import mindustry.ui.*; - -public class LStatements{ - - public static class AssignStatement extends LStatement{ - public int output; - public double value; - - @Override - public void run(LExecutor exec){ - - } - - @Override - public void build(Table table){ - table.field(value + "", Styles.nodeField, str -> value = parseDouble(str)) - .size(100f, 40f).pad(2f).color(table.color).padRight(20); - - table.field(value + "", Styles.nodeField, str -> value = parseDouble(str)) - .size(100f, 40f).pad(2f).color(table.color); - } - - @Override - public LCategory category(){ - return LCategory.operations; - } - - static double parseDouble(String s){ - return s.equals("yes") || s.equals("true") ? 1 : - s.equals("no") || s.equals("false") ? 0 : - Strings.parseDouble(s, 0); - } - } - - public static class OpStatement extends LStatement{ - public BinaryOp op = BinaryOp.add; - public int output; - public double result; - - @Override - public void run(LExecutor exec){ - - } - - @Override - public void build(Table table){ - - } - - @Override - public LCategory category(){ - return LCategory.operations; - } - } -} diff --git a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java b/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java index 46dfa695ae..971de2d887 100644 --- a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java +++ b/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java @@ -75,16 +75,16 @@ public class TractorBeamTurret extends Block{ } //look at target - if(target != null && target.within(this, range) && target.team() != team && target.type().flying){ + if(target != null && target.within(this, range) && target.team() != team && target.type().flying && efficiency() > 0.01f){ any = true; float dest = angleTo(target); - rotation = Angles.moveToward(rotation,dest, rotateSpeed * edelta()); + rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta()); lastX = target.x; lastY = target.y; strength = Mathf.lerpDelta(strength, 1f, 0.1f); if(damage > 0){ - target.damageContinuous(damage); + target.damageContinuous(damage * efficiency()); } //shoot when possible diff --git a/core/src/mindustry/world/consumers/Consumers.java b/core/src/mindustry/world/consumers/Consumers.java index febf111f53..99fff57632 100644 --- a/core/src/mindustry/world/consumers/Consumers.java +++ b/core/src/mindustry/world/consumers/Consumers.java @@ -52,8 +52,8 @@ public class Consumers{ } /** Creates a consumer which only consumes power when the condition is met. */ - public ConsumePower powerCond(float usage, Boolf cons){ - return add(new ConditionalConsumePower(usage, cons)); + public ConsumePower powerCond(float usage, Boolf cons){ + return add(new ConditionalConsumePower(usage, (Boolf)cons)); } /**