Many various logic changes

This commit is contained in:
Anuken
2020-08-10 14:19:24 -04:00
parent b28e7de1db
commit ea8dccdfb2
16 changed files with 384 additions and 182 deletions

View File

@@ -39,7 +39,7 @@ import static mindustry.Vars.*;
@EntityDef(value = {Buildingc.class}, isFinal = false, genio = false, serialize = false) @EntityDef(value = {Buildingc.class}, isFinal = false, genio = false, serialize = false)
@Component(base = true) @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 //region vars and initialization
static final float timeToSleep = 60f * 1; static final float timeToSleep = 60f * 1;
static final ObjectSet<Building> tmpTiles = new ObjectSet<>(); static final ObjectSet<Building> tmpTiles = new ObjectSet<>();
@@ -1168,19 +1168,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
@Override @Override
public double sense(LSensor sensor){ public double sense(LAccess sensor){
if(sensor == LSensor.health) return health; if(sensor == LAccess.health) return health;
if(sensor == LSensor.efficiency) return efficiency(); if(sensor == LAccess.efficiency) return efficiency();
if(sensor == LSensor.totalItems && items != null) return items.total(); if(sensor == LAccess.rotation) return rotation;
if(sensor == LSensor.totalLiquids && liquids != null) return liquids.total(); if(sensor == LAccess.totalItems && items != null) return items.total();
if(sensor == LSensor.totalPower && power != null) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f); if(sensor == LAccess.totalLiquids && liquids != null) return liquids.total();
if(sensor == LSensor.itemCapacity) return block.itemCapacity; if(sensor == LAccess.totalPower && power != null) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
if(sensor == LSensor.liquidCapacity) return block.liquidCapacity; if(sensor == LAccess.itemCapacity) return block.itemCapacity;
if(sensor == LSensor.powerCapacity) return block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f; if(sensor == LAccess.liquidCapacity) return block.liquidCapacity;
if(sensor == LSensor.powerNetIn && power != null) return power.graph.getPowerProduced(); if(sensor == LAccess.powerCapacity) return block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
if(sensor == LSensor.powerNetOut && power != null) return power.graph.getPowerNeeded(); if(sensor == LAccess.powerNetIn && power != null) return power.graph.getPowerProduced();
if(sensor == LSensor.powerNetStored && power != null) return power.graph.getLastPowerStored(); if(sensor == LAccess.powerNetOut && power != null) return power.graph.getPowerNeeded();
if(sensor == LSensor.powerNetCapacity && power != null) return power.graph.getBatteryCapacity(); if(sensor == LAccess.powerNetStored && power != null) return power.graph.getLastPowerStored();
if(sensor == LAccess.powerNetCapacity && power != null) return power.graph.getBatteryCapacity();
return 0; return 0;
} }
@@ -1191,6 +1192,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return 0; 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 @Override
public void remove(){ public void remove(){
if(sound != null){ if(sound != null){

View File

@@ -70,9 +70,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
@Override @Override
public double sense(LSensor sensor){ public double sense(LAccess sensor){
if(sensor == LSensor.totalItems) return stack().amount; if(sensor == LAccess.totalItems) return stack().amount;
if(sensor == LSensor.health) return health; if(sensor == LAccess.health) return health;
return 0; return 0;
} }

View File

@@ -86,9 +86,9 @@ public class TypeIO{
}else if(object instanceof Building){ }else if(object instanceof Building){
write.b((byte)12); write.b((byte)12);
write.i(((Building)object).pos()); write.i(((Building)object).pos());
}else if(object instanceof LSensor){ }else if(object instanceof LAccess){
write.b((byte)13); write.b((byte)13);
write.s(((LSensor)object).ordinal()); write.s(((LAccess)object).ordinal());
}else{ }else{
throw new IllegalArgumentException("Unknown object type: " + object.getClass()); throw new IllegalArgumentException("Unknown object type: " + object.getClass());
} }
@@ -111,7 +111,7 @@ public class TypeIO{
case 10: return read.bool(); case 10: return read.bool();
case 11: return read.d(); case 11: return read.d();
case 12: return world.build(read.i()); 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); default: throw new IllegalArgumentException("Unknown object type: " + type);
} }
} }
@@ -303,7 +303,7 @@ public class TypeIO{
//make sure player exists //make sure player exists
if(player == null) return prev; if(player == null) return prev;
return player; return player;
}else if(type == 1){ }else if(type == 1){ //formation controller
int id = read.i(); int id = read.i();
return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null); return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null);
}else{ }else{

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -6,6 +6,7 @@ import arc.util.ArcAnnotate.*;
import mindustry.*; import mindustry.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.logic.LExecutor.*; import mindustry.logic.LExecutor.*;
import mindustry.logic.LStatements.*;
import mindustry.type.*; import mindustry.type.*;
/** "Compiles" a sequence of statements into instructions. */ /** "Compiles" a sequence of statements into instructions. */
@@ -39,7 +40,7 @@ public class LAssembler{
//store sensor constants //store sensor constants
for(LSensor sensor : LSensor.all){ for(LAccess sensor : LAccess.all){
putConst("@" + sensor.name(), sensor); putConst("@" + sensor.name(), sensor);
} }
} }
@@ -64,23 +65,49 @@ public class LAssembler{
} }
public static Seq<LStatement> read(String data){ public static Seq<LStatement> read(String data){
//empty data check
if(data == null || data.isEmpty()) return new Seq<>();
Seq<LStatement> statements = new Seq<>(); Seq<LStatement> statements = new Seq<>();
String[] lines = data.split("[;\n]+"); String[] lines = data.split("[;\n]+");
for(String line : lines){ for(String line : lines){
//comments //comments
if(line.startsWith("#")) continue; if(line.startsWith("#")) continue;
String[] tokens = line.split(" "); try{
LStatement st = LogicIO.read(tokens); //yes, I am aware that this can be split with regex, but that's slow and even more incomprehensible
Seq<String> 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){ if(st != null){
statements.add(st); statements.add(st);
}else{ }else{
//attempt parsing using custom parser if a match is found - this is for mods //attempt parsing using custom parser if a match is found - this is for mods
String first = tokens[0]; String first = arr[0];
if(customParsers.containsKey(first)){ if(customParsers.containsKey(first)){
statements.add(customParsers.get(first).get(tokens)); 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; return statements;
} }

View File

@@ -16,7 +16,6 @@ import arc.util.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.logic.LStatements.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.ui.dialogs.*; import mindustry.ui.dialogs.*;
@@ -56,12 +55,6 @@ public class LCanvas extends Table{
dialog.addCloseButton(); dialog.addCloseButton();
dialog.show(); dialog.show();
}).height(50f).left().width(400f).marginLeft(10f); }).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(){ private void drawGrid(){

View File

@@ -7,8 +7,7 @@ import mindustry.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.blocks.logic.LogicDisplay.*; import mindustry.world.blocks.logic.LogicDisplay.*;
import mindustry.world.blocks.storage.MessageBlock.*;
import static mindustry.world.blocks.logic.LogicDisplay.*;
public class LExecutor{ public class LExecutor{
//special variables //special variables
@@ -16,10 +15,16 @@ public class LExecutor{
varCounter = 0, varCounter = 0,
varTime = 1; varTime = 1;
public static final int
maxGraphicsBuffer = 512,
maxTextBuffer = 256;
public double[] memory = {}; public double[] memory = {};
public LInstruction[] instructions = {}; public LInstruction[] instructions = {};
public Var[] vars = {}; public Var[] vars = {};
public LongSeq graphicsBuffer = new LongSeq(); public LongSeq graphicsBuffer = new LongSeq();
public StringBuilder textBuffer = new StringBuilder();
public boolean initialized(){ public boolean initialized(){
return instructions != null && vars != null && instructions.length > 0; return instructions != null && vars != null && instructions.length > 0;
@@ -125,21 +130,30 @@ public class LExecutor{
void run(LExecutor exec); void run(LExecutor exec);
} }
/** Enables/disables a building. */ /** Controls a building's state. */
public static class EnableI implements LInstruction{ public static class ControlI implements LInstruction{
public int target, value; 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.target = target;
this.value = value; this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.p4 = p4;
} }
EnableI(){} ControlI(){}
@Override @Override
public void run(LExecutor exec){ public void run(LExecutor exec){
Building b = exec.building(target); Object obj = exec.obj(target);
if(b != null) b.enabled = exec.bool(value); 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(target instanceof Senseable){
if(sense instanceof Content){ if(sense instanceof Content){
output = ((Senseable)target).sense(((Content)sense)); output = ((Senseable)target).sense(((Content)sense));
}else if(sense instanceof LSensor){ }else if(sense instanceof LAccess){
output = ((Senseable)target).sense(((LSensor)sense)); 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 byte type;
public int target; public int target;
public int x, y, p1, p2, p3; 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.type = type;
this.target = target; this.target = target;
this.x = x; this.x = x;
@@ -303,7 +322,29 @@ public class LExecutor{
this.p3 = p3; this.p3 = p3;
} }
public DisplayI(){ public DrawI(){
}
@Override
public void run(LExecutor exec){
//graphics on headless servers are useless.
if(Vars.headless) return;
//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)));
}
}
}
public static class DrawFlushI implements LInstruction{
public int target;
public DrawFlushI(int target){
this.target = target;
}
public DrawFlushI(){
} }
@Override @Override
@@ -311,63 +352,69 @@ public class LExecutor{
//graphics on headless servers are useless. //graphics on headless servers are useless.
if(Vars.headless) return; if(Vars.headless) return;
if(type == commandFlush){
Building build = exec.building(target); Building build = exec.building(target);
if(build instanceof LogicDisplayEntity){ if(build instanceof LogicDisplayEntity){
//flush is a special command
LogicDisplayEntity d = (LogicDisplayEntity)build; LogicDisplayEntity d = (LogicDisplayEntity)build;
for(int i = 0; i < exec.graphicsBuffer.size; i++){ for(int i = 0; i < exec.graphicsBuffer.size; i++){
d.commands.addLast(exec.graphicsBuffer.items[i]); d.commands.addLast(exec.graphicsBuffer.items[i]);
} }
exec.graphicsBuffer.clear(); exec.graphicsBuffer.clear();
} }
}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 PrintI implements LInstruction{ public static class PrintI implements LInstruction{
private static final StringBuilder out = new StringBuilder(); public int value;
public int value, target; public PrintI(int value){
public PrintI(int value, int target){
this.value = value; this.value = value;
this.target = target;
} }
PrintI(){} PrintI(){}
@Override @Override
public void run(LExecutor exec){ 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 //this should avoid any garbage allocation
Var v = exec.vars[value]; Var v = exec.vars[value];
if(v.isobj && value != 0){ if(v.isobj && value != 0){
if(v.objval instanceof String){ String strValue = v.objval instanceof String ? (String)v.objval : v.objval == null ? "null" : "[object]";
b.handleString(v.objval);
}else if(v.objval == null){ exec.textBuffer.append(strValue);
b.handleString("null");
}else{ }else{
b.handleString("[object]");
}
}else{
out.setLength(0);
//display integer version when possible //display integer version when possible
if(Math.abs(v.numval - (long)v.numval) < 0.000001){ if(Math.abs(v.numval - (long)v.numval) < 0.000001){
out.append((long)v.numval); exec.textBuffer.append((long)v.numval);
}else{ }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);
} }
} }
} }

View File

@@ -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();
}

View File

@@ -7,6 +7,7 @@ import arc.scene.*;
import arc.scene.actions.*; import arc.scene.actions.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.gen.*; import mindustry.gen.*;
@@ -27,9 +28,8 @@ public abstract class LStatement{
public LStatement copy(){ public LStatement copy(){
StringBuilder build = new StringBuilder(); StringBuilder build = new StringBuilder();
write(build); write(build);
String[] split = build.toString().split(" "); Seq<LStatement> read = LAssembler.read(build.toString());
LStatement result = LogicIO.read(split); return read.size == 0 ? null : read.first();
return result == null && LAssembler.customParsers.containsKey(split[0]) ? LAssembler.customParsers.get(split[0]).get(split) : result;
} }
//protected methods are only for internal UI layout utilities //protected methods are only for internal UI layout utilities

View File

@@ -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") @RegisterStatement("write")
public static class WriteStatement extends LStatement{ public static class WriteStatement extends LStatement{
public String to = "0"; public String to = "0";
@@ -90,7 +108,7 @@ public class LStatements{
@RegisterStatement("draw") @RegisterStatement("draw")
public static class DrawStatement extends LStatement{ 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"; public String x = "0", y = "0", p1 = "0", p2 = "0", p3 = "0";
@Override @Override
@@ -105,13 +123,13 @@ public class LStatements{
table.button(b -> { table.button(b -> {
b.label(() -> type.name()); b.label(() -> type.name());
b.clicked(() -> showSelect(b, CommandType.allNormal, type, t -> { b.clicked(() -> showSelect(b, GraphicsType.all, type, t -> {
type = t; type = t;
rebuild(table); rebuild(table);
}, 2, cell -> cell.size(100, 50))); }, 2, cell -> cell.size(100, 50)));
}, Styles.logict, () -> {}).size(90, 40).color(table.color).left().padLeft(2); }, Styles.logict, () -> {}).size(90, 40).color(table.color).left().padLeft(2);
if(type != CommandType.stroke){ if(type != GraphicsType.stroke){
table.row(); table.row();
} }
@@ -158,7 +176,6 @@ public class LStatements{
} }
}).expand().left(); }).expand().left();
} }
@Override @Override
@@ -168,13 +185,13 @@ public class LStatements{
@Override @Override
public LInstruction build(LAssembler builder){ 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") @RegisterStatement("drawflush")
public static class FlushStatement extends LStatement{ public static class DrawFlushStatement extends LStatement{
public String target = "display"; public String target = "@0";
@Override @Override
public void build(Table table){ public void build(Table table){
@@ -189,7 +206,102 @@ public class LStatements{
@Override @Override
public LInstruction build(LAssembler builder){ 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 //sensors
new Table(i -> { new Table(i -> {
for(LSensor sensor : LSensor.all){ for(LAccess sensor : LAccess.senseable){
i.button(sensor.name(), Styles.cleart, () -> { i.button(sensor.name(), Styles.cleart, () -> {
stype("@" + sensor.name()); stype("@" + sensor.name());
hide.run(); 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") @RegisterStatement("bop")
public static class BinaryOpStatement extends LStatement{ public static class BinaryOpStatement extends LStatement{
public BinaryOp op = BinaryOp.add; 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") @RegisterStatement("jump")
public static class JumpStatement extends LStatement{ public static class JumpStatement extends LStatement{
public transient StatementElem dest; public transient StatementElem dest;

View File

@@ -3,6 +3,6 @@ package mindustry.logic;
import mindustry.ctype.*; import mindustry.ctype.*;
public interface Senseable{ public interface Senseable{
double sense(LSensor sensor); double sense(LAccess sensor);
double sense(Content content); double sense(Content content);
} }

View File

@@ -3,6 +3,7 @@ package mindustry.world.blocks.defense;
import arc.Graphics.*; import arc.Graphics.*;
import arc.Graphics.Cursor.*; import arc.Graphics.Cursor.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
@@ -12,6 +13,8 @@ import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.logic.*;
import mindustry.world.blocks.defense.Door.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -33,6 +36,11 @@ public class Door extends Wall{
Sounds.door.at(base); Sounds.door.at(base);
for(DoorEntity entity : base.chained){ for(DoorEntity entity : base.chained){
//skip doors with things in them
if((Units.anyEntities(entity.tile) && !open) || entity.open == open){
continue;
}
entity.open = open; entity.open = open;
pathfinder.updateTile(entity.tile()); pathfinder.updateTile(entity.tile());
entity.effect(); 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(){ public void effect(){
(open ? closefx : openfx).at(this); (open ? closefx : openfx).at(this);
} }
@@ -104,7 +125,7 @@ public class Door extends Wall{
@Override @Override
public void tapped(Player player){ public void tapped(Player player){
if((Units.anyEntities(tile) && open) || !timer(timerToggle, 30f)){ if((Units.anyEntities(tile) && open) || !timer(timerToggle, 40f)){
return; return;
} }

View File

@@ -18,6 +18,7 @@ import mindustry.entities.bullet.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
@@ -25,9 +26,12 @@ import mindustry.world.consumers.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
import mindustry.world.meta.values.*; import mindustry.world.meta.values.*;
import static mindustry.Vars.tilesize; import static mindustry.Vars.*;
public abstract class Turret extends Block{ 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 final int timerTarget = timers++;
public int targetInterval = 20; public int targetInterval = 20;
@@ -140,8 +144,9 @@ public abstract class Turret extends Block{
public class TurretEntity extends Building implements ControlBlock{ public class TurretEntity extends Building implements ControlBlock{
public Seq<AmmoEntry> ammo = new Seq<>(); public Seq<AmmoEntry> ammo = new Seq<>();
public int totalAmmo; public int totalAmmo;
public float reload, rotation = 90, recoil, heat; public float reload, rotation = 90, recoil, heat, logicControlTime = -1;
public int shotCounter; public int shotCounter;
public boolean logicShooting = false;
public @Nullable Posc target; public @Nullable Posc target;
public Vec2 targetPos = new Vec2(); public Vec2 targetPos = new Vec2();
public @NonNull BlockUnitc unit = Nulls.blockUnit; public @NonNull BlockUnitc unit = Nulls.blockUnit;
@@ -152,11 +157,26 @@ public abstract class Turret extends Block{
unit.tile(this); 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 @Override
public Unit unit(){ public Unit unit(){
return (Unit)unit; return (Unit)unit;
} }
public boolean logicControlled(){
return logicControlTime > 0;
}
@Override @Override
public void draw(){ public void draw(){
Draw.rect(baseRegion, x, y); Draw.rect(baseRegion, x, y);
@@ -184,6 +204,10 @@ public abstract class Turret extends Block{
unit.rotation(rotation); unit.rotation(rotation);
unit.team(team); unit.team(team);
if(logicControlTime > 0){
logicControlTime -= Time.delta;
}
if(hasAmmo()){ if(hasAmmo()){
if(timer(timerTarget, targetInterval)){ if(timer(timerTarget, targetInterval)){
@@ -193,10 +217,11 @@ public abstract class Turret extends Block{
if(validateTarget()){ if(validateTarget()){
boolean canShoot = true; boolean canShoot = true;
//player behavior if(isControlled()){ //player behavior
if(isControlled()){
targetPos.set(unit.aimX(), unit.aimY()); targetPos.set(unit.aimX(), unit.aimY());
canShoot = unit.isShooting(); canShoot = unit.isShooting();
}else if(logicControlled()){ //logic behavior
canShoot = logicShooting;
}else{ //default AI behavior }else{ //default AI behavior
BulletType type = peekAmmo(); BulletType type = peekAmmo();
float speed = type.speed; float speed = type.speed;

View File

@@ -19,8 +19,7 @@ public class LogicDisplay extends Block{
commandRect = 4, commandRect = 4,
commandLineRect = 5, commandLineRect = 5,
commandPoly = 6, commandPoly = 6,
commandLinePoly = 7, commandLinePoly = 7;
commandFlush = 8;
public int maxSides = 25; public int maxSides = 25;
@@ -91,7 +90,7 @@ public class LogicDisplay extends Block{
} }
} }
public enum CommandType{ public enum GraphicsType{
clear, clear,
color, color,
stroke, stroke,
@@ -99,11 +98,9 @@ public class LogicDisplay extends Block{
rect, rect,
lineRect, lineRect,
poly, poly,
linePoly, linePoly;
flush;
public static final CommandType[] all = values(); public static final GraphicsType[] all = values();
public static final CommandType[] allNormal = Seq.select(all, t -> t != flush).toArray(CommandType.class);
} }
@Struct @Struct

View File

@@ -109,8 +109,8 @@ public class NuclearReactor extends PowerGenerator{
} }
@Override @Override
public double sense(LSensor sensor){ public double sense(LAccess sensor){
if(sensor == LSensor.heat) return heat; if(sensor == LAccess.heat) return heat;
return super.sense(sensor); return super.sense(sensor);
} }